I'm making a package to collect some functions in the same place. But while I attempt to create the body it always has an error.
I have tried everything I know, but it doesn´t matter how much do I try it always gives me the same error
This is my package which does not bring me any error.
create or replace PACKAGE talde_paquete AS
procedure editaldeak(Equipo Taldeak.Kod_taldea%TYPE, Nombre Taldeak.izena%TYPE, Localidad Taldeak.Herria%TYPE, Correo taldeak.helbide_elektronikoa%TYPE,Campo Taldeak.Zelaia%TYPE);
procedure equipopartidos(Equipo partidak.talde1%TYPE);
END talde_paquete;
And this is my package body which is the one who brings me always the same error
CREATE OR REPLACE PACKAGE BODY talde_paquete
IS
procedure editaldea(Equipo Taldeak.Kod_taldea%TYPE, Nombre Taldeak.izena%TYPE, Localidad Taldeak.Herria%TYPE, Correo taldeak.helbide_elektronikoa%TYPE,Campo Taldeak.Zelaia%TYPE)
AS
VTaldea NUMBER(1);
Taldenoexist EXCEPTION;
BEGIN
SELECT COUNT(Kod_Taldea) INTO VTaldea FROM Taldeak WHERE Kod_Taldea=Equipo;
IF VTaldea=1 THEN
UPDATE Taldeak SET Izena=Nombre, Herria=Localidad, Helbide_Elektronikoa=Correo, Zelaia=Campo WHERE Kod_taldea=Equipo;
ELSE
RAISE Taldenoexist;
END IF;
EXCEPTION
WHEN Taldenoexist THEN
DBMS_OUTPUT.PUT_LINE('Taldea ez da existitzen');
END editaldea;
procedure equipopartidos(Equipo partidak.talde1%TYPE)
IS
CURSOR PartidoEquipo IS
SELECT Talde1, Talde2, P_Data FROM Partidak WHERE Talde1 LIKE Equipo OR Talde2 LIKE Equipo;
E1 Partidak.Talde1%TYPE;
E2 Partidak.Talde2%TYPE;
Fecha Partidak.P_Data%TYPE;
existe NUMBER(3);
Taldexist EXCEPTION;
BEGIN
SELECT COUNT(Talde1) INTO existe FROM partidak WHERE Talde1=Equipo OR Talde2=Equipo;
IF (existe>0)THEN
OPEN PartidoEquipo;
FETCH PartidoEquipo INTO E1,E2,Fecha;
WHILE PartidoEquipo%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(E1||' taldeak '||E2||' taldearen aurka jokatuko du '||Fecha);
FETCH PartidoEquipo INTO E1,E2,Fecha;
END LOOP;
CLOSE PartidoEquipo;
ELSE
RAISE Taldexist;
END IF;
EXCEPTION
WHEN Taldexist THEN
DBMS_OUTPUT.PUT_LINE('Taldea ez da existitzen');
END equipopartidos;
END talde_paquete;
/
And here is the error that I get when I'm attempting to run the body script.
LINE/COL ERROR
--------- -------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
1/14 PLS-00905: object BIZKAIABASKET.TALDE_PAQUETE is invalid
1/14 PLS-00304: cannot compile body of 'TALDE_PAQUETE' without its specification
Errors: check compiler log
#hotfix is absolutely right, the error message when compiling is quite clear. The definition of the procedures in the body must be the same as the one defined in the header, I notice that there is a difference in the name editaldeak vs editaldea
Related
I'm trying to create a package with procedures to insert rows in my tables.
The package header:
CREATE OR REPLACE PACKAGE pkg_developers
AS
PROCEDURE empty_tables;
PROCEDURE add_city(country IN CITIES.COUNTRY%type, zipcode IN CITIES.ZIPCODE%type, city IN CITIES.CITY%type);
END pkg_developers;
package body:
CREATE OR REPLACE PACKAGE BODY pkg_developers AS
PROCEDURE empty_tables
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE cities CASCADE';
/* More truncate statements*/
DBMS_OUTPUT.put_line('Tables truncated successfully.');
END empty_tables;
PROCEDURE add_city(p_country IN cities.COUNTRY%type, p_zipcode IN cities.ZIPCODE%type, p_city IN cities.CITY%type)
IS
BEGIN
INSERT INTO CITIES(COUNTRY, ZIPCODE, city) VALUES(p_country, p_zipcode, p_city);
COMMIT;
END add_city;
END pkg_developers;
How I Execute the procedures:
BEGIN
pkg_developers.empty_tables();
pkg_developers.add_city('Country', '1111', 'City');
END;
The error I get:
[2022-04-16 11:41:48] [72000][4063]
[2022-04-16 11:41:48] ORA-04063: package body "PROJECT.PKG_DEVELOPERS" has errors
[2022-04-16 11:41:48] ORA-06508: PL/SQL: could not find program unit being called: "PROJECT.PKG_DEVELOPERS"
[2022-04-16 11:41:48] ORA-06512: at line 2
[2022-04-16 11:41:48] Position: 0
[2022-04-16 11:41:48] Summary: 1 of 1 statements executed, 1 failed in 15 ms (106 symbols in file)
I did find out that if I remove the parameters for the procedure add_city and hardcode the values it does work, but I can't for the life of me figure out what would be wrong with the parameters, I've looked at examples online and they seem identical to me.
I've also tried to call the exact same procedure but not inside the package and then it works fine as well.
Read what it says:
package body "PROJECT.PKG_DEVELOPERS" has errors
You can't call an invalid package (well, you can - as you already did - but you know the outcome).
So, what's wrong? At first sight, this:
Package specification says:
PROCEDURE add_city (country IN CITIES.COUNTRY%type,
zipcode IN CITIES.ZIPCODE%type,
city IN CITIES.CITY%type);
Package body says:
PROCEDURE add_city (p_country IN cities.COUNTRY%type,
p_zipcode IN cities.ZIPCODE%type,
p_city IN cities.CITY%type)
Find the difference. If you can't, then: in package body, all parameters have prefix p_ (which is correct, i.e. better than declaration in package specification). Whichever option you choose (I suggest the owe with a prefix), use it in both specification and body.
I am sure my question has a simple theoretical answer but I cannot find it.
I have a procedure which accepts as parameter a NUMBER. It also have the VALUE_ERROR and OTHERS exceptions:
create or replace procedure test( p1 number) is
begin
null;
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'others');
end;
I am executing the procedure with a VARCHAR2 paramter:
execute test('a');
... an I expect that the error message displayed to be
ORA-20001 value_error
but, unfortunately, I got:
Error report - ORA-06502: PL/SQL: numeric or value error: character to
number conversion error ORA-06512: at line 1
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
Can anyone explain this, or share a link where it is explained why I do not receive expected error message?
Thank you very much,
As Nicholas mentioned you don't get your message because the exception is thrown not inside the procedure but before executing it.
Let's look at an example:
create or replace procedure test( p1 number) is
begin
null;
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'PROC value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'PROC others');
end;
/
begin
test('a');
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'OUT value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'OUT others');
end;
What happens here is that you're calling a procedure that requires number as parameter so Oracle tries conversion during execution of anonymous block. You can't see the message from the procedure because before entering the procedure the conversion exception is thrown.
Now let's see what happens if we change the procedure:
create or replace procedure test( p1 varchar2) is
param number;
begin
param := p1;
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'PROC value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'PROC others');
end;
/
begin
test('a');
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'OUT value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'OUT others');
end;
Or just:
begin
test('a');
end;
to see the error thrown in the procedure.
Now the procedure requires number within its body; when execution reaches that point it throws the conversion error, from within the procedure itself.
When I try to compile this package, I get the error: PLS-00103: Encountered the symbol “BEGIN” when expecting one of the following: end function pragma procedure subtype type current cursor delete exists prior
Can anyone help me, please?
CREATE OR REPLACE PACKAGE PCK_TB_ESTADO
IS
PROCEDURE PRC_INSERE
(P_NM_REDE_FUNCIONARIO IN TB_FUNCIONARIO.NM_REDE_FUNCIONARIO%TYPE,
P_DS_ESTADO IN TB_ESTADO.DS_ESTADO%TYPE,
P_ID_UF IN TB_ESTADO.ID_UF%TYPE,
P_MENS OUT VARCHAR2)
BEGIN
CREATE SEQUENCE SEQ_ESTADO
MINVALUE 1
MAXVALUE 99
START WITH 1
INCREMENT BY 1;
INSERT INTO TB_ESTADO
VALUES (SEQ_ESTADO.NEXTVAL,P_DS_ESTADO,P_ID_UF,SYSDATE,P_NM_REDE_FUNCIONARIO);
COMMIT;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK;
P_MENS := 'Você tentou executar um comando INSERT ou UPDATE que criou um valor duplicado em um campo restrito por um index único.';
WHEN OTHERS THEN
ROLLBACK;
P_MENS := 'Erro.';
END;
END PCK_TB_ESTADO;
Here are the Issues:
A Package Specification only contains the signature of the procedures/functions it is supposed to contain. The code for the procs/functions goes into the Package Body
You cannot have a DDL statement directly inside your Procedure. You can however execute DDLs using EXECUTE IMMEDIATE
The Procedure definition in the Package Body should have IS/AS keyword before BEGIN
Is it a bad practice to do what the code below does? Will bad things happen to me for writing it?
Edit: this is just an example. I would not use dbms_output for any real error reporting.
CREATE OR REPLACE PACKAGE my_package
AS
PROCEDURE master;
END;
/
CREATE OR REPLACE PACKAGE BODY my_package
AS
my_global_interrupt EXCEPTION;
PROCEDURE my_private_procedure
IS
BEGIN
-- in case some flag is raised, raise exception to stop process and prepare for resume
RAISE my_global_interrupt;
END;
PROCEDURE master
IS
BEGIN
my_private_procedure;
EXCEPTION
WHEN my_global_interrupt THEN
dbms_output.put_line('global interrupt, ');
-- prepare to resume
END;
END;
/
On the contrary globally defined user exceptions is good practice. Consider the following skeleton of a package body.
create or replace package body my_pkg
as
my_x1 exception;
my_x2 exception;
my_x3 exception;
PROCEDURE p1 is
begin
...
exception
when no_data_found then raise my_x1;
end p1;
PROCEDURE p2 is
begin
...
exception
when no_data_found then raise my_x2;
end p2;
PROCEDURE p3 is
begin
...
exception
when no_data_found then raise my_x3;
end p3;
PROCEDURE master is
begin
p1;
p2;
p3;
exception
when my_x1 then do_this;
when my_x2 then do_that;
when my_x3 then do_the_other;
end master;
end my_pkg;
/
The use of globally declared exceptions makes exception handling in the master procedure easier.
Also, bear in mind that sometimes we want to propagate the exception beyond the package, to say a program which calls our publicly declared procedure. We can do that by defining our exceptions in the package spec. This means other proecdures can reference them...
SQL> begin
2 my_pkg.master;
3 exception
4 when my_pkg.my_public_x1
5 then dbms_output.put_line('oh no!');
6 end;
7 /
oh no!
PL/SQL procedure successfully completed.
SQL>
We can also associate such exceptions with specific error numbers, so that they are recognisable even if the calling procedure doesn't explicitly handled them.
SQL> exec my_pkg.master
BEGIN my_pkg.master; END;
*
ERROR at line 1:
ORA-20999:
ORA-06512: at "APC.MY_PKG", line 32
ORA-06512: at line 1
SQL>
That's (slightly) more helpful than the generic ORA-06510 error.
Looks reasonable enough to me, provided you're happy that after the interrupt condition it's OK to resume processing. If you are going to log the interrupt in some way, it's probably better to insert a row into a log table using an autonomous transaction. You won't see anything from DBMS_OUTPUT until the whole procedure finishes. Then you'll see all the DBMS_OUTPUT at once.
Suppose I have a PL/SQL function that selects one value from a table. If the query returns no records, I wish for the NO_DATA_FOUND error to propagate (so that the calling code can catch it), but with a more meaningful error message when SQLERRM is called.
Here is an example of what I am trying to accomplish:
FUNCTION fetch_customer_id(customer_name VARCHAR2) RETURN NUMBER;
customer_id NUMBER;
BEGIN
SELECT customer_id
INTO customer_id
FROM CUSTOMERS
WHERE customer_name = fetch_customer_id.customer_name;
RETURN customer_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
meaningful_error_message := 'Customer named ' || customer_name || ' does not exist';
RAISE;
END;
Is there a way to associate meaningful_error_message with the NO_DATA_FOUND error?
Update: It has been suggested that I use RAISE_APPLICATION_ERROR to raise a custom error code when NO_DATA_FOUND is encountered. The purpose of this question was to determine if this technique could be avoided so that the calling code can catch NO_DATA_FOUND errors rather than a custom error code. Catching NO_DATA_FOUND seems more semantically correct, but I could be wrong.
Use RAISE_APPLICATION_ERROR (-20001, 'your message');
This will return an error number -20001, and your message instead of the NO_DATA_FOUND message. Oracle has reserved the error numbers between -20001 and -210000 for user use in their applications, so you won't be hiding another Oracle error by using these numbers.
EDIT: RAISE_APPLICATION_ERROR is specifically designed to allow you to create your own error messages. So Oracle does not have another method of allowing dynamic error messages. To further refine this you can define your own exception in the package where you define your procedure. Add the following:
CUSTOMER_NO_DATA_FOUND EXCEPTION;
EXCEPTION_INIT (CUSTOMER_NO_DATA_FOUND, -20001);
In your procedure code, you do the RAISE_APPLICATION_ERROR, and the client code can do a
WHEN CUSTOMER_NO_DATA_FOUND THEN which looks better, and they still have the error message captured in SQLERRM.
As suggested by Thomas you can use RAISE_APPLICATION_ERROR. If you also want to keep the NO_DATA_FOUND error on the error stack you can add TRUE as a third parameter to the function:
DECLARE
l NUMBER;
BEGIN
SELECT NULL INTO l FROM dual WHERE 1 = 2;
EXCEPTION
WHEN no_data_found THEN
raise_application_error(-20001, 'Meaningful Message', TRUE);
END;
ORA-20001: Meaningful Message
ORA-06512: at line 8
ORA-01403: no data found (*)
The line tagged (*) is the original error message.