User-defined function with IN VARCHAR parameter in PL/SQL Oracle [closed] - sql

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I need some help. It is the first time when I am asking for help here, so please excuse me for my bad english. I am so mad, because I can not figure out how to fix this error. I work in Oracle 10g. The output is:
Function created.
No errors.
Function created.
Enter value for v_numes: 'SECTIA1' --SECTIA1 is the name of section(department) from sectii table
Sectia exista in baza de date SECTIA1
Numele sectiei este: SECTIA1 --the name of the department(v_numes)
DECLARE
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "SYSTEM.FUNCTION0", line18
ORA-01403: no data found
ORA-06512: at line 17
Here it is my code:
set serveroutput on
set verify off
CREATE OR REPLACE FUNCTION function0(p_section_name VARCHAR) RETURN NUMBER IS
v_procent1 CONSTANT REAL:=0.01;
v_cods sectii.cods%TYPE;--the table is named sectii, which means sections
v_ok1 NUMBER:=1;
BEGIN
DBMS_OUTPUT.PUT_LINE('Numele sectiei este: '||p_section_name);
SELECT cods
INTO v_cods
FROM sectii
WHERE den=UPPER(p_section_name);
DBMS_OUTPUT.PUT_LINE('Codul sectiei pentru '||p_section_name||' este '||v_cods);
RETURN (v_ok1);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
RETURN 'Prea multe sectii cu acest nume.';
WHEN NO_DATA_FOUND THEN
RETURN 'Nici o sectie cu acest nume.';
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20011,'Unknown Exception in function0');
END function0;
/
show errors;
/
DECLARE
v_numes VARCHAR2(255);
v_numesu VARCHAR2(255);
v_numesl VARCHAR2(255);
v_boool NUMBER:=1;
e_invalid_section EXCEPTION;
BEGIN
v_numes:=&v_numes;
IF SQL%NOTFOUND THEN
RAISE e_invalid_section;
ELSE
DBMS_OUTPUT.PUT_LINE('Sectia exista in baza de date '|| v_numes);
END IF;
v_numesu:=UPPER(v_numes);
v_numesl:=LOWER(v_numes);
IF v_numes=v_numesl OR v_numes=v_numesu THEN
DBMS_OUTPUT.PUT_LINE('FUNCTION0 '||function0(v_numes));
END IF;
--v_numes:=TO_CHAR(v_numes);
--DBMS_OUTPUT.PUT_LINE('RETURN FUNCTIE0: '||v_boool);
EXCEPTION
WHEN e_invalid_section THEN --exceptie definita de utilizator
DBMS_OUTPUT.PUT_LINE('Nu exista aceasta sectie in tabelul sectii.');
END;
/

The declaration of FUNCTION0, states that the function returns a number:
CREATE OR REPLACE FUNCTION function0(p_section_name VARCHAR) RETURN NUMBER IS
The return statements in your exception blocks return characters...
EXCEPTION
WHEN TOO_MANY_ROWS THEN
RETURN 'Prea multe sectii cu acest nume.';
WHEN NO_DATA_FOUND THEN
RETURN 'Nici o sectie cu acest nume.';
One thing to note, your error was extremely specific:
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "SYSTEM.FUNCTION0", line18
ORA-01403: no data found
ORA-06512: at line 17
This means you're converting a character to a number at line 18 and a NO_DATA_FOUND exception was raised at line 17...
To answer all of your comments in one place, you're getting a NO_DATA_FOUND exception because of the WHERE clause, as I've already said.
WHERE den = UPPER(p_section_name)
Run this SELECT statement:
select * from cods where den = upper(den)
It will not return any rows because it is not true. If you're uppercasing the parameter p_section_name you also need to uppercase the column den. You need to search case-insensitively, see Case insensitive searching in Oracle for more details.

Related

Error While generating pascal's triangle in plSQL

well I'm pretty new to plSQL and I can't seem to figure out some errors I'm getting while trying to generate a pascal's triangle
Here's the code:
SET SERVEROUTPUT ON;
DECLARE
N NUMBER;
I NUMBER;
J NUMBER;
K NUMBER;
L NUMBER;
T NUMBER;
S NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('ENTER THE LIMIT');
N:=&N;
I:=0;
T:=N-2;
S:=0;
L:=0;
WHILE (I<N) LOOP
J:=0;
WHILE (J<T) LOOP
DBMS_OUTPUT.PUT(' ');
J:=J+1;
END LOOP;
K:=0;
WHILE (K<=S) LOOP
IF (K<=I) THEN
DBMS_OUTPUT.PUT(K+1);
L:=K;
ELSE
L:=L-1;
DBMS_OUTPUT.PUT(L+1);
END IF;
K:=K+1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
T:=T-1;
S:=S+2;
END LOOP;
END;
The errors are
Error report -
ORA-20000: ORU-10027: buffer overflow, limit of 1000000 bytes
ORA-06512: at "SYS.DBMS_OUTPUT", line 32
ORA-06512: at "SYS.DBMS_OUTPUT", line 97
ORA-06512: at line 29
20000. 00000 - "%s"
*Cause: The stored procedure 'raise_application_error'
was called which causes this error to be generated.
*Action: Correct the problem as described in the error message or contact
the application administrator or DBA for more information.
Neither I nor N are ever updated, so you have an infinite loop. Other than that, the error is indicating that the DBMS_OUTPUT buffer is being exceeded. It's default buffer size is 1,000,000 bytes, though you can adjust that with an appropriate DBMS_OUTPUT.ENABLE call or SET SERVEROUTPUT SIZE statement.
The problem you're having has to do with SQL*Plus, the Oracle SQL client, rather than PL/SQL, the programming language. Change the line which says SET SERVEROUTPUT ON to
SET SERVEROUTPUT ON SIZE UNLIMITED
This error may, however, indicate you've got an infinite loop, so be careful. Note that I never appears to be incremented and N is never decremented, so the loop started at WHILE (I<N) LOOP may not terminate.
Best of luck.

how do I get PL PGSQL error code in a function?

I am writing a PL/PGSQL function and it produces an error. I want to print the error with RAISE NOTICE statement but I don't know how to get the error code? What variable holds the last error?
This is my sample code:
IF FOUND
THEN
BEGIN
insert into app.company(dateinserted,name) values(now(),company_name) returning comnpany_id;
return company_id;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Insert failed with...';
return -2;
END;
ELSE
RETURN -1;
END IF;
This code will return company_id if insert was successful and print the error if it fails.
...
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Insert failed with error code %', SQLSTATE;
...
Read more in the documentation.
include SQLERRM to get an error message.

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.

Character string buffer too small error in Oracle Stored Procedure

I am getting an error in an Oracle 11g stored procedure. The error is...
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
It is happening at line 31, the line that contains out_cnt_tot := 0; I'm really not sure why there is anything wrong with that line. Another programmer created this procedure and I'm really not familiar with SQL procedures. Can anyone help me figure this out?
create or replace
PROCEDURE "FIP_BANKREC_PREP"
(
in_file_date in varchar2,
in_bank_code in varchar2,
out_cnt_apx_miss_no out integer,
out_cnt_prx_miss_no out integer,
out_cnt_apx_no_mtch out integer,
out_cnt_prx_no_mtch out integer,
out_cnt_ap_dup out integer,
out_cnt_pr_dup out integer,
out_cnt_bad out integer,
out_cnt_ap_load out integer,
out_cnt_pr_load out integer,
out_cnt_ap_not_load out integer,
out_cnt_pr_not_load out integer,
out_cnt_tot out integer,
out_message out varchar2
) as
file_date date;
ap_acct_no varchar2(16);
pr_acct_no varchar2(16);
-- ------------------------------------------------------
-- begin logic
-- ------------------------------------------------------
begin
file_date := to_date(in_file_date,'yyyymmdd');
out_cnt_tot := 0; --- THE ERROR IS ON THIS LINE ---
out_message := 'Test Message';
select brec_acct_code into ap_acct_no
from MSSU.zwkfi_bankrec_accts
where brec_acct_bank = in_bank_code
and brec_acct_type = 'AP';
select brec_acct_code into pr_acct_no
from MSSU.zwkfi_bankrec_accts
where brec_acct_bank = in_bank_code
and brec_acct_type = 'PR';
// The rest of the procedure...
Simple demo of the scenario mentioned in comments:
create or replace procedure p42(out_message out varchar2) as
begin
out_message := 'Test message';
end p42;
/
If I call that with a variable that is declared big enough, it's fine. I have a 12-char variable, so assigning a 12-char value is not a problem:
declare
msg varchar2(12);
begin
p42(msg);
end;
/
anonymous block completed
But if I make a mistake and make the caller's variable too small I get the error you're seeing:
declare
msg varchar2(10);
begin
p42(msg);
end;
/
Error report:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "STACKOVERFLOW.P42", line 3
ORA-06512: at line 4
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause:
*Action:
The error stack shows both the line in the procedure that errored (line 3), and the line in the caller that triggered it (line 4). Depending on where you're calling it you might not have the whole stack, of course.
You mentioned that there would be various error messagesin the future. You need to make sure that anything that ever calls this defines the variables to be big enough to cope with any of your messages. If they were stored in a table you could semi-automate that, otherwise it'll be a manual code review check.
OK, saw your c# comment after posting this. It looks like you're calling this constructor; that doesn't say what default size it gets, but not unreasonable to think it might be 1. So you need to call this constructor instead to specify the size explicitly:
OracleParameter(String, OracleType, Int32)
Initializes a new instance of the OracleParameter class that uses the parameter name,
data type, and length.
... something like:
OracleParameter prm15 = new OracleParameter("out_str_message",
OracleDbType.Varchar2, 80);
Unless there's a way to reset the size after creation, which I can't see. (Not something I've ever used!).

error invalid number ORA-01722 in Procedure [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have a procedure like below, but when I tried to running it using sqlplus its gave me error
BEGIN IB_ARCHIVE_FDS('FDS_LOG', 'TIME_REQUEST', 5, 6); END;
ERROR at line 1: ORA-01722: invalid number ORA-06512: at "NIAGA.IB_ARCHIVE_FDS", line 10 ORA-06512: at line 1
and I'm using Oracle 9i
CREATE OR replace PROCEDURE Ib_archive_fds(table_name VARCHAR2,
column_name VARCHAR2,
success_period NUMBER,
active_period NUMBER)
IS
TYPE fds_tabs
IS TABLE OF ib_fds_log%ROWTYPE INDEX BY PLS_INTEGER;
TYPE fds_message_id
IS TABLE OF ib_fds_log.message_id%TYPE INDEX BY PLS_INTEGER;
v_fds_log FDS_TABS;
v_message_id FDS_MESSAGE_ID;
BEGIN
SELECT *
bulk collect INTO v_fds_log
FROM ib_fds_log2
WHERE direction = 0
AND status_fds_message = 0
AND time_request < Trunc(SYSDATE - ' || SUCCESS_PERIOD || ' - 1);
FOR i IN 1 .. v_fds_log.last LOOP
V_message_id(i) := V_fds_log(i).message_id;
END LOOP;
forall indx IN 1 .. v_fds_log.count
INSERT INTO ib_fds_log3
VALUES V_fds_log(indx);
COMMIT;
forall indx IN 1 .. v_fds_log.count
DELETE FROM ib_fds_log2
WHERE message_id = V_message_id(indx);
COMMIT;
END;
can somebody help me to solve my problem here.
While I agree with David's analysis of the shortcomings of your implementation the actual cause of that error message is this bug:
time_request < trunc(sysdate - ' || SUCCESS_PERIOD || '- 1);
SUCCESS_PERIOD is a parameter and you presumably want to use it in your date calculation. However you have coded it as a string; a string is not a number and so we cannot use in in a substraction.
I'm not quite sure what arithmetic you're trying to achieve, but I think you want either this ...
time_request < trunc(sysdate - ( SUCCESS_PERIOD - 1));
... or this ...
time_request < trunc(sysdate - ( SUCCESS_PERIOD + 1) );
... depending on how you want to modify the value of SUCCESS_PERIOD.
This code should almost certainly avoid the cursors completely and just use SQL statements -- something along the lines of ...
procedure ib_archive_fds(
table_name varchar2,
column_name varchar2,
success_period number ,
active_period number )
is
time_request_limit date;
begin
time_request_limit := trunc(sysdate - success_period - 1)
insert into
ib_fds_log3
select
*
from
ib_fds_log2
where
direction = 0 and
status_fds_message = 0 and
time_request < ib_archive_fds.time_request_limit;
delete from
ib_fds_log2
where
direction = 0 and
status_fds_message = 0 and
time_request < ib_archive_fds.time_request_limit;
end;
Various enhancements would be possible if the result set of the query is not constant when this is executed, but all of the PL/SQL is just asking for errors and performance problems.