Oracle 11g PL/SQL Positions of CONTANT variables in PACKAGE - plsql

I have strictly optimization problem. where in my PACKAGE I should place CONSTANT variables when procedure/function is being called many times ?
Let's look at this:
CREATE OR REPLACE PACKAGE WB_TEST IS
PROCEDURE TEST;
END WB_TEST;
CREATE OR REPLACE PACKAGE BODY WB_TEST IS
FUNCTION PARSER(IN_PARAM IN VARCHAR2) RETURN VARCHAR2 IS
LC_MSG CONSTANT VARCHAR2(80) := 'Hello USERNAME! How are you today?';
LC_PARAM CONSTANT VARCHAR2(10) := 'USERNAME';
BEGIN
RETURN REPLACE(LC_MSG, LC_PARAM, IN_PARAM);
END PARSER;
PROCEDURE TEST IS
BEGIN
FOR I IN 1 .. 1000 LOOP
DBMS_OUTPUT.PUT_LINE(PARSER(TO_CHAR(I)));
END LOOP;
END TEST;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
END WB_TEST;
/
Or is better to do something like that:
CREATE OR REPLACE PACKAGE WB_TEST IS
PROCEDURE TEST;
END WB_TEST;
CREATE OR REPLACE PACKAGE BODY WB_TEST IS
GC_MSG CONSTANT VARCHAR2(80) := 'Hello USERNAME! How are you today?';
GC_PARAM CONSTANT VARCHAR2(10) := 'USERNAME';
FUNCTION PARSER(IN_PARAM IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN REPLACE(GC_MSG, GC_PARAM, IN_PARAM);
END PARSER;
PROCEDURE TEST IS
BEGIN
FOR I IN 1 .. 1000 LOOP
DBMS_OUTPUT.PUT_LINE(PARSER(TO_CHAR(I)));
END LOOP;
END TEST;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
END WB_TEST;

It is extremely unlikely to matter from a performance standpoint. The code the PL/SQL compiler generates should be identical in both cases-- the constants will almost certainly get compiled inline where they are referenced.
The only reason to prefer one over the other would be code clarity and variable scoping. If the constants are really local to the PARSER function-- if they aren't likely to be useful to other methods in the package, they ought to be declared as part of the function. If, on the other hand, they are likely to be useful to other methods in the package, they ought to be declared as part of the package body. If they are likely to be useful to methods outside the package, they ought to be declared as part of the package specification.

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;
/

How to achive PLSQL procedure overloading package

I have a use case where a package has 2 procedure with the same name and argument, one as CHAR type and another is VARCHAR2 type.
How to call tham?
For PL/SQL the package spec and body compiles ok.
But at runtime the 2 procedures are the same and there is no way to distinguish because CHAR type and VARCHAR2 type are of the same datatype family.
For example:
create or replace package pk_over
is
procedure pr_text(p_isbCaracter char);
procedure pr_text(p_isbCaracter varchar2);
End;
create or replace package body pk_over
is
procedure pr_text(p_isbCaracter char)
is
Begin
Dbms_Output.Put_Line('Soy PR_TEXT parámetro CHAR="'||p_isbCaracter||chr(34));
End pr_text;
--
procedure pr_text(p_isbCaracter varchar2)
is
Begin
Dbms_Output.Put_Line('Soy PR_TEXT parámetro VARCHAR2="'||p_isbCaracter||chr(34));
End pr_text;
--
End pk_over;
An you call with:
Declare
sbVar2 varchar2(20);
Begin
sbVar2:='Texto 1';
pk_over.pr_text(sbVar2);
End;
The error at runtime is:
PLS-00307: too many declarations of 'PR_TEXT' match this call
So you don't need the 2 procedures, only one.

I am unable to create a plsql function inside a while loop.Is it possible to write plsql function inside while loop?

create or replace FUNCTION ACHEHBBDA40(p_sum_date IN VARCHAR2) RETURN NUMBER AS
CURSOR BISNES_T_INFO IS
SELECT a.TARGETID, a.CLIENTID,b.BSNSID
FROM CLIENT_XREF_T a
INNER JOIN BISNES_T b
ON
a.CLIENTID = b.CLIENTID AND
a.TYPE = '1' AND
b.WORKKBN = '0';
BEGIN
DBMS_OUTPUT.PUT_LINE('PGM_NAME');
LOOP
BEGIN
FETCH BISNES_T_INFO
INTO l_compid,l_bsnsid,l_clientid;
--beginning of nested function in declaration section
FUNCTION getClientXref(l_clientid VARCHAR2) RETURN Number AS
CURSOR CLIENT_XREF_T_INFO IS
SELECT d.BRNO, d.TRNO
FROM CLIENT_XREF_T x INNER JOIN CLIENT_T c ON x.CLIENTID = c.CLIENTID;
BEGIN
OPEN CLIENT_XREF_T_INFO;
FETCH CLIENT_XREF_T_INFO
INTO l_brno,l_trno
END;
return 1;
END getClientXref;
UTL_FILE.PUT_LINE(v_filehandle,l_compid ||CHR(9)|| l_brno ||CHR(9)|| l_trno);
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Close the file after the process is over
DBMS_OUTPUT.PUT_LINE('MSGID_ERREND : ' ||commonUtilities.GC_MSGID_ERREND);
DBMS_OUTPUT.PUT_LINE('MSG_ERREND : ' ||commonUtilities.GC_MSG_ERREND);
DBMS_OUTPUT.PUT_LINE('MSGID_NO_DATA : ' ||commonUtilities.GC_MSGID_NO_DATA);
DBMS_OUTPUT.PUT_LINE('MSG_NO_DATA : ' ||commonUtilities.GC_MSG_NO_DATA);
RETURN lc_failure;
EXIT;
END;
END LOOP;
When i create the nested function getClientXref inside the while loop its throws the compile time error "Error(213,21): PLS-00103: Encountered the symbol "GETCLIENTXREF" when expecting one of the following: := . ( # % ; " in sql developer.
Honestly I don't understand the purpose of the code you posted: it never calls the function you are trying to declare... But, since your question is about syntax, I have to correct what all other posters and commentators are saying:
You CAN declare procedures and functions inside a loop
The following code works!
begin
for c in (select * from dict) loop
DECLARE
-- procedure inside a loop
procedure local_print_current_row is
begin
-- here I am even accessing the external
-- "c" for loop variable
dbms_output.put_line(c.table_name || ' -> ' || c.comments);
end;
BEGIN
local_print_current_row;
END;
end loop;
end;
of course this is just a "toy" example to illustrate the syntax, but PL/SQL allows you to nest declarations (not only of variables) almost everywhere using the declare/begin/exception/end construct.
in your code you wrote the comment "--beginning of nested function in declaration section ", but you didn't actually define any nested declaration section. you need the DECLARE keyword.
A lot of people do not realize that in PL/SQL "begin/end" is not simply the same of "{"/"}" in java. The complete syntax of the begin/end block allows all these parts:
DECLARE
<declarations>
BEGIN
<code>
EXCEPTION
<exception handlers>
END
It is just optional to write the "DECLARE" and "EXCEPTION" sections, but the BEGIN/END block is actually made of all the above parts.
in any DECLARE section you can declare:
function and procedures
types
cursors
variables
exceptions
...
and all the things you declare in that section will be visible only within the corresponding begin[/exception]/end sections.
Moreover you can nest other blocks wherever you can write actual "runnable" code. This kind of nesting can be done:
declare
...
begin
declare
procedure MyLocalProc is
procedure NestedProc is
begin
end;
begin
....
declare
...
begin
...
exception
..
end
...
exception
end
begin
...
end
exception when others then
declare
...
begin
...
end
end
P.S.:Note that after a "procedure is" or "function ... is" the "DECLARE" section is implicit: this is why you can start declaring stuff immediately after a procedure/function declaration without writing "declare". This does not happen for triggers, where you actually have to write "declare" if you want to add local declarations.
I don't really get it why you have to create a function inside your while loop. Functions were not really meant for that kind of approach. You can just create your function separately and call it each time you needed inside your while loop and pass your parameters.

how would I enter this function into toad to run?

Here is the code
vResult VARCHAR2(200);
BEGIN
fvData:=TRIM(fvData);
IF SUBSTR(fvData,LENGTH(fvData)-1,1)<>'*' THEN
fvData:=fvData||'**';
END IF;
vResult:=SUBSTR(fvData,1,InStr(fvData,'^^') - 1);
fvData:=SUBSTR(fvData,InStr(fvData,'^^') + 3);
RETURN vResult;
END StringExtract;
/
I have tried entering different ways, with fvdata=365 but nothing happens, I have try entering small SQL like
select InStr(367,'^^^^') - 1
from dual;
but I can't figure out how to do this big function.
In an attempt to help you get this working take a look at the following code. I have left out the detail of your function so we don't complicate things but you should be able to just plug that back in.
DECLARE
inputValue VARCHAR2(200) := :inputValue; -- << this bind variable allows you to provide different input each you run the code
FUNCTION stringExtract(fvData varchar2) RETURN varchar2
IS
vResult VARCHAR2(200);
BEGIN
vResult := TRIM(fvData);
RETURN vResult;
END stringExtract;
BEGIN
DBMS_OUTPUT.PUT_LINE(LENGTH(inputValue));
DBMS_OUTPUT.PUT_LINE(LENGTH(stringExtract(inputValue)));
END;
Hopefully you can take that as a template and adapt to get your program running.

Retrieve Database Constants

I want to retrieve database constants through query in front end to fill this constant string in DropDownList.
I have tried following query
select pr_Package.constant_String from dual;
Suggestions are welcome.
You can't reference a packaged constant directly in a SQL statement.
You can add a function to your package that returns the constant and call that function from SQL. Something like this will work (though you may want to consider moving the constant to the package body rather than the package specification once you have a function to return the data).
create or replace package pkg_const
as
some_constant number;
function get_constant
return number;
end;
create or replace package body pkg_const
as
function get_constant
return number
is
begin
return some_constant;
end;
end;
select pkg_const.get_constant from dual;

Resources