ORA-06512: at "SYS.UTL_FILE", line 536 - sql

We're getting the following error in an SQL procedure on Ubuntu. The same procedure is executing properly on Windows. The goal of the procedure is to import a .csv file into an external oracle table.
The Oracle error:
ORA-29283: invalid file operation ORA-06512: at "SYS.UTL_FILE", line 536 ORA-29283: invalid file operation
This SO question might have been a solution, but even after giving proper permissions chmod 777 (which solved the issue in that case) to the files concerned we are facing the same error.
ORA-29283: invalid file operation ORA-06512: at "SYS.UTL_FILE", line 536
The concerned portion of the procedure is :
for i in c loop
dbms_output.put_line('Inside for loop');
select count(file_name) into f_n from t_filenames_exp e where i.file_name=e.file_name;
if f_n=0 then
dbms_output.put_line('Inside if statement');
insert into t_filenames_exp(file_name,status) values(i.file_name,'need_to_read');
select f_id into f_idn from t_filenames_exp e where e.file_name=i.file_name;
select substr(i.file_name,instr(i.file_name,'exp_'),4) into fchk from dual;
select to_char(to_date(to_char(SEQ_DATE,'dd-MON-yyyy'),'dd-MON-yyyy'),'D') into v_sufix from M_LAB_ID_SEQ_TAB;
if(fchk='exp_') then
file_handle := UTL_FILE.FOPEN('EXP_DATA',i.file_name,'R');
file_handle1 := UTL_FILE.FOPEN('EXP','staging.txt','W');
loop
begin
utl_file.get_line(file_handle,output_line);
utl_file.put_line(file_handle1,output_line);
exception when no_data_found then
exit;
end;
end loop;
if utl_file.is_open(file_handle) then
utl_file.fclose(file_handle);
end if;
if utl_file.is_open(file_handle1) then
utl_file.fclose(file_handle1);
end if;
/*insert into t_files_data_exp(f_id,patient_last_name,patient_name,patient_id_code,method_internal_index,method_acronym,index_repeat,result,unit_of_measurement,minimum_reference_value,maximum_reference_value,date_)
select f_idn,patient_last_name,patient_name,(patient_id_code ||'H'||v_sufix),method_internal_index,method_acronym,index_repeat,result, unit_of_measurement,minimum_reference_value,maximum_reference_value,date_ from files_data;*/
insert into t_files_data_exp(f_id,patient_last_name,patient_name,patient_id_code,method_internal_index,method_acronym,index_repeat,result,unit_of_measurement,minimum_reference_value,maximum_reference_value,date_)
select f_idn,'Unknown','Unknown',(r.patient_id_code ||'H'||v_sufix),m.CANONICAL_ID,r.METHOD_ACRONYM,0,r.RESULT,r.unit_of_measurement,'','','' from files_data r ,M_METHODS_EXP m where m.METHOD_ACRONYM=r.METHOD_ACRONYM;
else
file_handle := UTL_FILE.FOPEN('EXP_DATA',i.file_name,'R');
file_handle1 := UTL_FILE.FOPEN('EXP','staging1.txt','W');
loop
begin
utl_file.get_line(file_handle,output_line);
utl_file.put_line(file_handle1,output_line);
exception when no_data_found then
exit;
end;
end loop;
if utl_file.is_open(file_handle) then
utl_file.fclose(file_handle);
end if;
if utl_file.is_open(file_handle1) then
utl_file.fclose(file_handle1);
end if;
insert into t_files_data_exp(f_id,patient_last_name,patient_name,patient_id_code,method_internal_index,method_acronym,index_repeat,result,unit_of_measurement,minimum_reference_value,maximum_reference_value,date_)
select f_idn,'Unknown','Unknown',r.PATIENT_ID_CODE,m.CANONICAL_ID,r.METHOD_ACRONYM,0,r.RESULT,r.unit_of_measurement,'','','' from rfiles_data r ,M_METHODS_EXP m where m.METHOD_ACRONYM=r.METHOD_ACRONYM;
end if;
-- Check whether the data in csv file is same as data in external table.
if trace='on' then
if(fchk='expr_') then
dbms_output.put_line('**************************************************');
select i.file_name,count(*) into filename,rows_in_file from files_data;
dbms_output.put_line('File name :'||filename);
dbms_output.put_line('Total no of rows :'||rows_in_file);
select replace(filename,'exp','_exp') into new_filename from dual;
file_handle2 := UTL_FILE.FOPEN('EXP_LOG',new_filename,'W');
for i1 in cur loop
/*data:=to_char (i1.patient_last_name||';'||i1.patient_name||';'||i1.patient_id_code||';'||i1.method_internal_index||';'||i1.method_acronym||';'||i1.index_repeat||';'||i1.result||';'||i1.unit_of_measurement||';'||i1.minimum_reference_value||';'||i1.maximum_reference_value||';'||i1.date_);*/
data:=to_char(i1.patient_id_code||';'||i1.method_acronym||';'||i1.result||';'||i1.unit_of_measurement);
utl_file.put_line(file_handle2,data);
end loop;
else
dbms_output.put_line('**************************************************');
select i.file_name,count(*) into filename,rows_in_file from rfiles_data;
dbms_output.put_line('File name :'||filename);
dbms_output.put_line('Total no of rows :'||rows_in_file);
select replace(filename,'expr','_expr') into new_filename from dual;
file_handle2 := UTL_FILE.FOPEN('EXP_LOG',new_filename,'W');
for i1 in cur1 loop
/*data:=to_char (i1.m_id||';'||i1.date_||';'||i1.METHOD_ACRONYM||';'||i1.PATIENT_ID_CODE||';'||i1.TEST_TYPE||';'||i1.UNIT_OF_MEASUREMENT||';'||i1.RESULT||';'||i1.RESULT_FLAG); */
data:=to_char(i1.patient_id_code||';'||i1.method_acronym||';'||i1.result||';'||i1.unit_of_measurement);
utl_file.put_line(file_handle2,data);
end loop;
end if;
if utl_file.is_open(file_handle2) then
utl_file.fclose(file_handle2);
end if;
dbms_output.put_line('*************************************************');
end if;
end if;
end loop;
The line on which the error is occurring is:
file_handle := UTL_FILE.FOPEN('EXP_DATA',i.file_name,'R');
The permissions given to the file is as follows:
-rwxrwxrwx 1 rama rama 240 Feb 26 11:24 exp_41_02_2016.csv`
How to trace the problem which is causing this issue?
Please let me know if you want any other information?

It's an o/s file error...likely from permissions. The owner of the database shadow process that is executing the package is the o/s owner that needs permissions -- that's probably 'oracle'. You can test by logging in as 'oracle' on the database server and see if you can read the file in question. #alex poole offers a great thought to check the permissions of all parent directories.

Related

Having hard time figuring out the best attribute to use with cursor

Using this attribute %NOTFOUND with this cursor is giving me issues. I also tried using %FOUND. Is There a better option? It keeps returning the Else even if the cursor comes back with something in it or not. I want it to send the first email if the cursor has something and the second one if the cursor has nothing.
CURSOR crs IS
select *
from user_objects
where status = 'INVALID';
BEGIN
OPEN crs;
Loop
FETCH crs bulk collect INTO messages limit 10;
EXIT WHEN message. count = '0';
End IF;
for indx in messages.FIRST .. messages.LAST
loop
email_body := email_body||CHR(10)||'OBJECT NAME: '||messages(indx).OBJECT_NAME||', OBJECT TYPE: '||messages(indx). OBJECT_TYPE||', STATUS: '||messages(indx).STATUS;
end loop;
END LOOP;
IF CRS%NOTFOUND THEN
Email_body := email_body||CHR(10)|| '' ||CHR(10)||'All of these objects are invalid in your database. Please troubleshoot the issue. Thank you.'
DBMS_OUTPUT_LINE(email_body||'Invalid obj.';
ELSE
Email_body := 'There are no invalid objects in your database. Thank You.';
DBMS_OUTPUT_LINE(email_body||'No Invalid obj.';
END IF;
You can try this for test (i think more readable and shorter):
declare
email_body varchar2( 4000 ) := '';
l_invalid_objects_list varchar2( 4000 ) := '';
begin
l_invalid_objects_list := '';
for i in ( select OBJECT_NAME, OBJECT_TYPE, STATUS from user_objects where status = 'INVALID' and rownum <= 10 ) --limited to 10 records
loop
l_invalid_objects_list := l_invalid_objects_list||CHR(10)||'OBJECT NAME: '||i.OBJECT_NAME||', OBJECT TYPE: '||i. OBJECT_TYPE||', STATUS: '||i.STATUS;
end loop;
if length( l_invalid_objects_list ) > 0 then
email_body := email_body||CHR(10)|| '' ||CHR(10)||l_invalid_objects_list||CHR(10)|| '' ||CHR(10)||'All of these objects are invalid in your database. Please troubleshoot the issue. Thank you.';
DBMS_OUTPUT.PUT_LINE(email_body||'Invalid obj.');
else
Email_body := 'There are no invalid objects in your database. Thank You.';
DBMS_OUTPUT.PUT_LINE(email_body||'No Invalid obj.');
end if;
end;
I'm assuming you want to use a bulk operation and that you want to do this in batches of 10 even though it might be overkill for the functionality.
So . . . you need to declare a table type based on the cursor (ROWTYPE) then declare a variable based on the type.
You want to add to the email_body for each object and when you've looped through the lot it looks like you want another message saying if there were any invalid objects.
Using %NOTFOUND is not right here as you exit your loop when the messages.COUNT = 0. When it is 0 the cursor will always be %NOTFOUND so you're always getting the INVALID option.
I've used a boolean that is set to TRUE as soon as you have at least one invalid object and that is checked instead of the %NOTFOUND.
DECLARE
CURSOR crs
IS
SELECT *
FROM user_objects
WHERE status = 'INVALID';
TYPE work_recs IS TABLE OF crs%ROWTYPE;
messages work_recs;
lbol_invalid_objects BOOLEAN := FALSE;
email_body VARCHAR2(2000);
BEGIN
OPEN crs;
LOOP
FETCH crs BULK COLLECT INTO messages LIMIT 10;
DBMS_OUTPUT.PUT_LINE('COUNT - '||messages.COUNT);
EXIT WHEN messages.COUNT = '0';
lbol_invalid_objects := TRUE;
FOR indx IN messages.FIRST .. messages.LAST
LOOP
email_body := email_body||CHR(10)||'OBJECT NAME: '||messages(indx).OBJECT_NAME||', OBJECT TYPE: '||messages(indx). OBJECT_TYPE||', STATUS: '||messages(indx).STATUS;
END LOOP;
END LOOP;
IF lbol_invalid_objects THEN
email_body := email_body||CHR(10)|| '' ||CHR(10)||'All of these objects are invalid in your database. Please troubleshoot the issue. Thank you.'
dbms_output.put_line('Invalid obj.');
ELSE
email_body := 'There are no invalid objects in your database. Thank You.';
dbms_output.put_line('No Invalid obj.');
END IF;
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;

ORA-21700: object does not exist or is marked for delete

I have package with Period and TableOfPeriod types:
TYPE Period
IS RECORD
( StartPeriod Date,
EndPeriod Date
);
TYPE TableOfPeriod
IS TABLE OF Period;
and in this package I have three simple function:
FUNCTION Temp1
RETURN TableOfPeriod IS
returnedValue TableOfPeriod := TableOfPeriod();
BEGIN
returnedValue.extend(1);
returnedValue(1).StartPeriod := sysdate-100;
returnedValue(1).EndPeriod := sysdate;
RETURN returnedValue;
END Temp1;
FUNCTION CalculateFine
return VARCHAR2
IS
freewillLockTableRP TableOfPeriod:=TableOfPeriod();
compulsoryLockTableRP TableOfPeriod:=TableOfPeriod();
BEGIN
--for testing
compulsoryLockTableRP:=Temp1();
FOR i IN compulsoryLockTableRP.FIRST..compulsoryLockTableRP.LAST LOOP
IF(((compulsoryLockTableRP(i).EndPeriod - compulsoryLockTableRP(i).StartPeriod)>1)) THEN
BEGIN
-- RAISE_APPLICATION_ERROR(-20001, 'Hello world');
SELECT T111.StartPeriod StartPeriod,
T111.EndPeriod EndPeriod
bulk collect into freewillLockTableFull
FROM TABLE(DistributeDaysByPeriods(compulsoryLockTableRP, 5)) T111;
END;
END IF;
END LOOP;
/*SELECT T111.StartPeriod StartPeriod,
T111.EndPeriod EndPeriod
-- BULK COLLECT INTO compulsoryLockTableRP
bulk collect into freewillLockTableFull
FROM TABLE(DistributeDaysByPeriods(compulsoryLockTableRP, 5)) T111;*/
--===========
--SOME OTHER PROCESSING
RETURN 'Ok '
|| '#r';
EXCEPTION
WHEN No_Data_Found THEN return 'No data found#g';
-- WHEN OTHERS THEN RETURN SQLERRM;
END CalculateFine;
When I execute this function, I have next error:
"ORA-21700: object does not exist or is marked for delete ORA-06512:
at "MyPackageName", line 1181 ORA-06512: at line 1
21700. 00000 - "object does not exist or is marked for delete""
where 1181 line is a line with Select statement of CalculateFine function. Can anybody tell me, whats wrong and how I can solve this problem?
Check if you have in the same folder where your package is located a file with the same name but with an extention *.~sql (e.g.: your_file_name.~sql). I had the same error but after I have deleted an *.~sql file I could compile my package without ORA errors.

raise_application_error exception handling in subprocedures

I have multiple stored procedures calling multiple stored procedures in my database. To give a small example, I've constructed a fictionalised version of a few of them below. In my example, a Java program calls calculate_bill, which calls calculate_commission, which calls update_record.
I'm hoping to get some advice on how best to propagate the error messages up the stack to the calling Java layer, so the user gets a precise error message corresponding to wherever the error has occurred.
I'm really quite stuck on this. I've played around in my example with raise_application_error and just continually shuffling it up the stack. Is the way I'm doing it below remotely correct? Or is one raise_application_error in the relevant procedure enough, with no pragma exception init etc needed?
To give an idea of what I mean, in the example below, if a user entered a number which corresponded to a record which couldn't be updated because it didn't exist, I'd like them to get the message:
"Error calculating bill. Error calculating commission. No record exists to be updated" or something to that effect.
So two questions:
What is the best practice, most efficient, most tidy way to pass error messages up the stack for the end user in the application layer?
Does anyone have any suggestions on tidier output from the code, i.e. the best way to concatenate these errors to make them more meaningful? I'm really open to any suggestions on how to make this work best as I have absolutely no prior experience in this.
Example:
(Error in code):
-20000 : Error in top level procedure
-20001 : Error in middle level procedure
-20002 : Error in bottom level procedure
Java code:
try {
// call calculate_bill
exception (SQLException ex)
// output oracle code and relevant message.
Oracle code:
create or replace procedure calculate_bill(in_num NUMBER)
is
error_calculating_commission EXCEPTION;
error_updating_record EXCEPTION;
PRAGMA EXCEPTION_INIT (error_calculating_commission, -20001);
PRAGMA EXCEPTION_INIT (error_updating_record , -20002);
begin
if in_num > 2 then
calculate_commission(in_num);
else
raise_application_error(-20000, 'Error calculating bill. ' || 'Record number doesn''t exist.', false);
end if;
exception
when error_calculating_commission then
raise_application_error(SQLCODE, 'Error calculating bill. ' || SQLERRM, false);
when error_updating_record then
raise_application_error(SQLCODE, 'Error calculating bill. ' || SQLERRM, false);
when others then
raise_application_error(-20000, 'Unknown error encountered calculating bill.', false);
end;
create or replace procedure calculate_commission(in_num NUMBER)
is
begin
if in_num < 30 then
raise_application_error(-20001, 'Number too small to calculate commission.', false);
elsif in_num >= 30 and < 40 then
declare
error_storing_record EXCEPTION;
PRAGMA EXCEPTION_INIT (error_storing_record , -20002);
begin
update_record(in_num);
exception
when error_storing_record then
raise_application_error(SQLCODE, 'Error calculating commission. ' || SQLERRM, false);
when others then
raise_application_error(-20001, 'Unknown error encountered calculating commission.', false);
else
raise_application_error(-20001, 'Number too large to calculate commission', false);
end if;
end;
create or replace procedure update_record(in_num NUMBER)
is
begin
//some SQL query with a where clause, where in_num equals something
exception
when no_data_found then
raise_application_error(-20002, 'No record exists to be updated', false);
when others then
raise_application_error(-20002, 'Unknown error encountered updating record.', false);
end if;
end;
Note: I know this example is a little contrived. I was just trying to keep it brief.
The way I would implement this is to use RAISE_APPLICATION_ERROR where the error actually originates, then leave it unhandled in the other layers (or, if you want to do logging in the database, catch it in the OTHERS section, then re-raise using RAISE rather than RAISE_APPLICATION_ERROR.
You're OTHERS sections are still perpetuating the problem raised in your previous question: when an unknown error occurs you're replacing it with a generic, unhelpful message. To paraphrase Tom Kyte, "a WHEN OTHERS that does not end in RAISE is a bug`.
With no logging in the database, I would re-write the provided code like this:
create or replace procedure calculate_bill(in_num NUMBER)
is
begin
if in_num > 2 then
calculate_commission(in_num);
else
raise_application_error(-20000, 'Error calculating bill. ' || 'Record number doesn''t exist.', false);
end if;
end;
create or replace procedure calculate_commission(in_num NUMBER)
is
begin
if in_num < 30 then
raise_application_error(-20001, 'Number too small to calculate commission.', false);
elsif in_num >= 30 and in_num < 40 then
update_record(in_num);
else
raise_application_error(-20001, 'Number too large to calculate commission', false);
end if;
end;
create or replace procedure update_record(in_num NUMBER)
is
v_stub number;
begin
select 1 into v_stub from dual where 1 = 0;
exception
when no_data_found then
raise_application_error(-20002, 'No record exists to be updated', false);
end;
Below is sample input and the stack traces they created:
exec calculate_bill(0)
ORA-20000: Error calculating bill. Record number doesn't exist.
ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 7
ORA-06512: at line 1
exec calculate_bill(10)
ORA-20001: Number too small to calculate commission.
ORA-06512: at "SCHEMANAME.CALCULATE_COMMISSION", line 5
ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 5
ORA-06512: at line 1
exec calculate_bill(35)
ORA-20002: No record exists to be updated
ORA-06512: at "SCHEMANAME.UPDATE_RECORD", line 8
ORA-06512: at "SCHEMANAME.CALCULATE_COMMISSION", line 7
ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 5
ORA-06512: at line 1
exec calculate_bill(100)
ORA-20001: Number too large to calculate commission
ORA-06512: at "SCHEMANAME.CALCULATE_COMMISSION", line 9
ORA-06512: at "SCHEMANAME.CALCULATE_BILL", line 5
ORA-06512: at line 1
If you were to add error logging to these procedures, it would be a simple matter of adding an OTHERS clause to the EXCEPTION sections:
WHEN OTHERS THEN
my_logging (SQLCODE, SQLERRM, DBMS_UTILITY.format_error_backtrace ());
RAISE;
The new exception created by your RAISE_APPLICATION_ERROR calls will be handled transparently by the RAISE.

PLS-00306: when calling a function from a PL/SQL block

I am getting the PLS-00306 error when I attempt to run a PL/SQL block that calls a variety of things including a function. The job of the function is to count how many cars belong to a certain model type. The function works if I call it in a SQL statement or it's own block, it just doesn't seem to work here.
This is the function:
CREATE OR REPLACE Function findtotalcarmodels(
model_name_in IN varchar2)
RETURN NUMBER
IS
counter NUMBER := 0;
CURSOR car_count_cur IS
SELECT model_name
FROM i_car
WHERE model_name = model_name_in;
Rec_car_details car_count_cur%ROWTYPE;
BEGIN
OPEN car_count_cur;
LOOP
FETCH car_count_cur INTO Rec_car_details;
EXIT WHEN car_count_cur%NOTFOUND;
counter := counter + 1;
END LOOP;
CLOSE car_count_cur;
RETURN counter;
END;
This is the Block:
SET SERVEROUTPUT ON FORMAT WRAP SIZE 12000
Declare
v_model VARCHAR2(40);
v_carcategory VARCHAR2(40);
v_totalcars NUMBER;
v_maxdate DATE:=TO_DATE(1, 'J');
Cursor carcur IS
SELECT *
FROM i_car;
CURSOR c1(v_car_registration VARCHAR2) IS
SELECT *
from i_booking a
WHERE a.registration=v_car_registration;
Begin
For car_rec in carcur
LOOP
v_maxdate:=TO_DATE(1, 'J');
for rec in c1(car_rec.registration)
loop
IF rec.date_reserved > v_maxdate
then
v_maxdate:=rec.date_reserved ;
If car_rec.Cost <=50000
THEN
v_carcategory := 'Budget Car';
End IF;
If car_rec.Cost BETWEEN 50000 AND 100000
THEN
v_carcategory := 'Standard Car';
End IF;
If car_rec.Cost >100000
THEN
v_carcategory := 'Premium Car';
End If;
end IF;
v_totalcars := findtotalcarmodels;
end loop;
DBMS_OUTPUT.PUT_LINE('Registration:'|| ' '|| car_rec.registration);
DBMS_OUTPUT.PUT_LINE('Cost:'|| ' $' || car_rec.Cost);
DBMS_OUTPUT.PUT_LINE('Model Name:'|| ' '|| car_rec.model_name);
DBMS_OUTPUT.PUT_LINE('Car Category:'|| ' '||v_carcategory);
DBMS_OUTPUT.PUT_LINE('Total number of Cars:'|| ' '||v_totalcars);
DBMS_OUTPUT.PUT_LINE('Most Recent Rental Date: '|| ' '||v_maxdate);
DBMS_OUTPUT.NEW_LINE;
END LOOP;
END;
/
Before I get slammed for the style of the PL/SQL block, just keep in mind that it is written to requirement and everything works well with the exception of the function.
If someone could point me in the right direction to call this function without error I would be very grateful.
It looks like you have missed to pass the IN parameter to the function.
Try like this,
v_totalcars := findtotalcarmodels('<model_name_in>');
Well, when i see things right, you don't fillup the parameter model_name. When you don't have an overriden function wihtout parameter you need to fill it up.
AS you can also see the PLS-00306 is telling you something about wrong number of arguments.