can't understand warnings in simple Pl/SQL function - plsql

I am using Oracle 10g with SqlDeveloper. When I execute the following code, it says
"FUNCTION wafadar compiled
Warning: execution completed with warning"
create or replace function wafadar
return varchar2(10)
is
cursor c1 is
SELECT employee_id,first_name FROM employees where department_id=50 ;
begin
for i in c1
loop
dbms_output.put_line(i.first_name);
end loop;
return 'hello';
end;
SHOW ERRORS at the end is also not showing the warnings. Why are the warnings there ?

Errors!
At first, you should care about errors, and I bet you have one on the return clause of your function (you can't specify the size of the "varchar2".
Warnings
Did you look for "warning" in the manuals?
http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/errors.htm#LNPLS00711
How to see warnings(enable categories you need)
alter function wafadar compile plsql_warnings='ENABLE:ALL' reuse settings
Check:
select plsql_warnings
from user_plsql_object_settings ps
where ps.name = 'WAFADAR'
Your warnings:
Client tools like sql*plus or Sql Developer(if supported):
show errors
or
select *
from user_errors ur
where ur.name = 'WAFADAR'
NAME TYPE SEQUENCE LINE POSITION TEXT ATTRIBUTE MESSAGE_NUMBER
------------------------------ ------------ ---------- ---------- ---------- -------------------------------------------------------------------------------- --------- --------------
WAFADAR FUNCTION 1 1 1 PLW-05018: unit WAFADAR omitted optional AUTHID clause; default value DEFINER us WARNING 5018
Finally, I suggest you to read a little bit of:
How to ask: http://www.catb.org/~esr/faqs/smart-questions.html#before
http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/toc.htm
All the "oracles" are here: http://tahiti.oracle.com/
Sql developer oracles(if you want to use it!): http://download.oracle.com/docs/cd/E11882_01/doc.112/e12152/toc.htm

Related

PLSQL Error in apex when compiling the following code- PLS-00103

I just referred to similar post related to same ORA & PLS error I faced, but still I can't resolve it using provided solution.
I get the following error: PLS-00103: Encountered the symbol “end-of-file” when expecting one of the following: begin function pragma procedure
My code:
create package PACHET is
procedure adaugaAngajat (v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type );
procedure modificaAngajat(v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type );
function verifica_telefon(v_tel angajati.telefon%type)
return boolean;
exp1 exception;
end;
create or replace package body PACHET is
procedure adaugaAngajat (v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type)
is
begin
if ( verifica_telefon(v_tel))
then
raise exp1;
else
insert into angajati values (v_id, v_idL, v_numeP, v_prenume, v_ore, v_sal, v_dat, v_tel, v_post);
end if;
exception
when exp1 then
dbms_output.put_line('Exista deja acest angajat!');
end;
As you tagged the question with Oracle Apex, I presume you're trying to create that package in its SQL Workshop. Of so, it can't execute more than a single statement at a time.
Therefore, put only package specification into the editor and run it. Then delete it and put package body into the editor and run that piece of code.
Alternatively, select (paint it blue) package spec statement and run it; then deselect it and select package body instead to run that statement.
PLS-00103, In short, this error means you have done some syntax error in your pl/SQL code, adding syntax that we should follow
--Firstly creating a declaration of a package
CREATE OR REPLACE PACKAGE PACHET
IS
PROCEDURE EXAMPLE(...);
.
.
END PACHET;
/
I think you have not ended the package and that is causing an error if I am not wrong or you have not pasted your full code, also you can add the name of the procedure or package with the end statements that would make it easy to follow the code.
Also first define the package(specs) and then run the body part.
create or replace package body PACHET is
procedure adaugaAngajat (v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type)
is
begin
if ( verifica_telefon(v_tel))
then
raise exp1;
else insert into angajati values (v_id, v_idL, v_numeP, v_prenume, v_ore, v_sal, v_dat, v_tel, v_post);
end if;
exception
when exp1 then
dbms_output.put_line('Exista deja acest angajat!');
end adaugaAngajat;
end PACHET;
/

Warning: Trigger created with compilation errors?

I am trying to implement Trigger that raises an User Defined Error Message and does not allow the update and Insert operation in the database.I am new to pl/sql i refereed some code from the internet and try to implement.My code is running is fine as i can not update/insert into database but still i am unable to get my user defined message and also i am getting this warning.
Warning: Trigger created with compilation errors ?
This is the table :
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER(5)
NAME VARCHAR2(20)
SALARY NUMBER(10)
DEPOT_ADDRESS VARCHAR2(15)
here is my code :
create or replace trigger cleaner_before_update_insert
for update or insert on cleaner
compound trigger
count binary_integer;
before statement is
begin
count:=0;
end before statement;
after each row is
begin
count :=count +1;
end after each row;
after statement is
begin
if count > 0 then
raise_application_error( -20001,'Update/insert operation can not be completed ');
end if;
end after statement;
end cleaner_before_update;
/
can anyone help me figure out what is the problem here and way to fix it.
thanks in advance.
Even after compilation of the code it is giving me this error.
ORA-06512: at "SYSTEM.CLEANER_BEFORE_UPDATE_INSERT", line 18
ORA-04088: error during execution of trigger
'SYSTEM.CLEANER_BEFORE_UPDATE_INSERT'
There are couple of problems with your TRIGGER block.
The name of the Trigger cleaner_before_update_insert does not match with the cleaner_before_update after the final end statement.
COUNT is an SQL keyword which is not allowed to be used as a variable in PL/SQL.You would receive the error - Error(10,11): PLS-00204: function or pseudo-column 'COUNT' may be used inside a SQL statement only
So, here is the modified code.
CREATE OR REPLACE TRIGGER cleaner_before_update_insert FOR UPDATE OR
INSERT ON cleaner compound TRIGGER
v_count binary_integer;
before STATEMENT
IS
BEGIN
v_count:=0;
END before STATEMENT;
AFTER EACH row
IS
BEGIN
v_count :=v_count +1;
END AFTER EACH row;
AFTER STATEMENT
IS
BEGIN
IF v_count > 0 THEN
raise_application_error( -20001,'Update/insert operation can not be completed ');
END IF;
END AFTER STATEMENT;
END cleaner_before_update_insert;
/

Highest record in PL/SQL

I have created a query that displays highest returned items from a table. My query it works perfectly with no errors! However, I want an efficient way of converting the query to PL/SQL block. The purpose of conversion is to handle errors.
SELECT ITEM_NO, MAX(QUANTITY) AS MAXIMUM
FROM ITEMS
WHERE CAT_NO >= (
SELECT MAX(ITEM_NUM) FROM ORDER
WHERE STATUS IN('ONE ITEM RETURNED','ALL ITEMS RETURNED')
)
GROUP BY ITEM_NO
ORDER BY ITEM_NO ASC;
Here's a way we do some exception handling in packages. I altered it to use your code as an example. Maybe you can use some ideas from it.
At the top, set a CONSTANT to the name of the procedure, and some variables to catch Oracle SQL error number and message in. Then in the body of the procedure, there is an anonymous block containing the select. First we set a variable to indicate where we are (err_loc) in case there are multiple locations where an error could be caught in one block. Then the select is issued. If an error occurs, it's caught by the EXCEPTION clause. Error info from Oracle is caught in the err* variables, the err_string is built and then emailed via the UTL_MAIL package. RAISE raises the error so the program halts. It's set up like this to be generic as possible, we can drop in the template, change the MBR_NAME, SQL, err_loc and that's it.
PROCEDURE TEST_PROC AS
MBR_NAME CONSTANT VARCHAR2(100) := 'TEST_PROC'; -- For use in error handling. Package member name.
err_nbr NUMBER; -- Holds a SQL error number if an exception occurs.
err_msg VARCHAR2(1000); -- Holds a SQL error message if an exception occurs.
err_string VARCHAR2(2000);
BEGIN
BEGIN
err_loc := 'Selecting max quantity'; -- Email subject
SELECT ITEM_NO, MAX(QUANTITY) AS MAXIMUM
FROM ITEMS
WHERE CAT_NO >= (SELECT MAX(ITEM_NUM)
FROM ORDER
WHERE STATUS IN('ONE ITEM RETURNED','ALL ITEMS RETURNED')
)
GROUP BY ITEM_NO
ORDER BY ITEM_NO ASC;
EXCEPTION
WHEN OTHERS THEN
err_nbr := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 1000);
err_string := 'ERROR: ' || err_nbr || ' occurred: ' || err_msg;
-- PKG_NAME and err_email_recip set in the body.
UTL_MAIL.send(sender => PKG_NAME||'.'||MBR_NAME||'#yourcompany.com',
recipients => err_email_recip,
subject => 'ERROR '|| err_loc,
message => CHR(13))||err_string);
RAISE;
END;
END TEST_PROC;
Have a look at cursors and records.
That way you have fetch data from the query and process the line if needed.
I don't have a database by hand to test my code, but this might give you an idea how a cursor and record work.
In order to capture a EXCEPTION you could add an exception handler and let it log the record you where busy with when the exception occured.
DECLARE
CURSOR CursorName IS
SELECT ColumnOne
FROM TableA
WHERE Name = 'Me';
RecordNumber CursorName%ROWTYPE;
BEGIN
-- Fetch the records from the cursor.
OPEN CursorName;
LOOP
FETCH CursorName INTO RecordNumber;
-- Do something with the record.
EXIT WHEN CursorName %NOTFOUND;
END LOOP;
CLOSE CursorName;
END;
/
Adding a error handeling would be done right above END:
EXCEPTION
WHEN OTHERS THEN
-- Log error message.
END;
/
Link: Error handeling
Does that answer you question a bit?

Unable to return query output in Apex PL SQL expression

I am trying to write a following PL/SQL function body for a dynamic action
The purpose of dynamic action is to set value for text area based on input parameters. Way I am trying to do it, is that setting the value into variable for different options
declare
P_NOTE varchar(100); -- derive value
P_WEBSERVER varchar(100); -- derive name
begin
-- for getting the P_NOTE value
select distinct note into P_NOTE from port_mapping where PLATFORM = :P3_PLATFORM and VERSION = :P3_VERSION;
-- for getting web server value
select CONCAT(P_NOTE,CONCAT('https-',:P3_CLIENT)) into P_WEBSERVER from dual order by 1;
if (:P3_PLATFORM = 'Apache') then
return P_WEBSERVER;
end if;
end;
However I am getting error
ORA-06550: line 15, column 5:
PLS-00372: In a procedure, RETURN statement cannot contain an expression
ORA-06550: line 15, column 5:
PL/SQL: Statement ignored
declare
P_NOTE varchar(100);
P_WEBSERVER varchar(100);
I am not sure what I am missing.
(Since you did not post any apex version this explanation deals with version 4.2)
If this -is- a dynamic action and the code you posted is in a true action of type 'Execute PL/SQL Code' then you can not use RETURN. The plsql block is not a function body (close, Mr Kemp!).
If you want to return values from the session state to page items then you need to use the "Page Items to Return" item of the true action.
This will put the session state of the defined page items into the value of the item on the page. This means that you can not use any variable to just put stuff in to be able to return it to the page, but you need to use an actual page item (after all, these are bind variables).
To clarify further, you would not write :
return P_WEBSERVER;
But you'd have to use a page item, say P3_WEBSERVER, and you'll need to create one if it doesn't exist of course:
:P3_WEBSERVER := p_webserver;
Of course you'd need to make sure that the correct value will be in there as you can not shortcircuit as you did in your code sample (p_webserver will usually hold a value even if the platform is not 'Apache') eg:
if (:P3_PLATFORM = 'Apache') then
:P3_WEBSERVER := P_WEBSERVER;
else
:P3_WEBSERVER := NULL;
end if;
Just read error message:
line 15, column 5
So, trouble caused by this line:
return P_WEBSERVER;
return not allowed in PL/SQL blocks, use output parameter to return a value.
Read Tom's answer to find out how to do that.

PL/SQL Blocks - seeing output simply ? [A Very simple question I'm sure !]

I'm sure what I want is very simple but I cannot figure out how.
I want :
To declare some variables and initialize them to certain values
To excecute a number of selects (predicated by the above variable values) and see the results as if i had executed the results straight on the sqlplus command line
I believe it's necessary to use the block structure in order that I may declare and make use of variables within the predicates of the queries. Although the examples shown here are quite simple in the real case there are numberous, much more complex SELECT's.
I tried doing this (forgetting about predicates for a moment) ...
DECLARE
EMP_EMPLOYEE_ID_IN VARCHAR2(12);
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM DEPT WHERE DEPNO';
END;
/
... but when I do that I get to execute the select without seeing the output.
I've also tried this ...
DECLARE
EMP_EMPLOYEE_ID_IN VARCHAR2(12);
BEGIN
SELECT * FROM DEPT;
END;
/
... but then I get ...
PLS-00428: an INTO clause is expected in this SELECT statement
... I really don't want to have to declare a variable for every column which would appear in my output.
Can anyone tell me how I can execute the SELECTs but simply and easily see the output as if I were on the sqlplus command line, ie to see the same output as if I did this
SQL> SELECT * FROM DEPT;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
Thanks
I have now tested the answer given by Shannon Severance below and found that it will do what I want.
For the sake of later readers I thought it might be useful to show the complete script here.
set line 32000;
set trimspool on;
var V_CURSOR1 REFCURSOR;
var V_CURSOR2 REFCURSOR;
var V_CURSOR3 REFCURSOR;
DECLARE
DEPT_NUM_IN VARCHAR2(12);
BEGIN
DEPT_NUM_IN := '10';
OPEN :V_CURSOR1 FOR SELECT * FROM DEPT;
OPEN :V_CURSOR2 FOR SELECT * FROM DEPT ORDER BY LOC;
OPEN :V_CURSOR3 FOR SELECT * FROM DEPT WHERE DEPTNO = DEPT_NUM_IN ORDER BY LOC;
END;
/
print V_CURSOR1
print V_CURSOR2
print V_CURSOR3
From sqlplus, other tools may be different.
First declare a sqlplus refcursor variable
SQL> var l_cursor refcursor
Then open that cursor within a PL/SQL block, where you will have access to declared variables and everything:
SQL> edit
Wrote file afiedt.buf
1 declare
2 l_number number;
3 begin
4 open :l_cursor for select table_name from all_tables where rownum < 10;
5* end;
SQL> /
PL/SQL procedure successfully completed.
Notice above that the refcursor variable is prepended with a :, this is because we are binding a sqlplus variable into the PL/SQL anonymous block
Next, use the SQLPLUS print command:
SQL> print l_cursor
TABLE_NAME
------------------------------
ICOL$
CON$
UNDO$
PROXY_ROLE_DATA$
FILE$
UET$
IND$
SEG$
COL$
9 rows selected.
DECLARE
v_result VARCHAR2(400);
BEGIN
SELECT dummy
INTO v_result
FROM dual;
dbms_output.put_line(v_result);
END;

Resources