Comments on: Wrong use of constant packages Friends of Oracle and Java Wed, 15 Apr 2015 12:11:59 +0000 hourly 1 By: Pasko Fri, 09 Feb 2007 17:04:37 +0000 Hi,
Great Discussion!
For existing Projects i would pick the Solution suggested by Andre.
I think it’s Great and Flexible.

Now,my suggestion for New Projects:
just create all Constants as Functions and write a Package Body for each Function
and return the respective Values for Constants.

This has the Advantage that it’s Type Safe because i can specify the Return Type in the Function.
The only Disadvantage here is that one has to write too much code :) but for this we could
write PL-SQL to generate this Package automatically by selecting from a Table where all our
constants are temporarily stored, for instance from table my_constants from Andre.

Oh, one more Disadvantage is that if we have a New Constant then we have to change the Package Spec and Body;
i would have preferred a Solution whereby a Constant Addition would not have necessitated a package Change.

So for example:

create or replace package my_constants
–my_name constant varchar2(30) := ‘Andre';
function my_name return varchar2 ;
function my_salary return number ;

create or replace package body my_constants

function my_name
return varchar2
return ‘Andre';
end ;

function my_salary
return number
return 200000;
end my_salary;
–add more functions for each new constant here

select my_constants.MY_NAME from dual

What do you think about this Solution?



By: mrskin Sat, 30 Sep 2006 22:12:16 +0000 Just wanted to say thanks for the article.

By: Niall Mc Phillips Mon, 12 Jun 2006 11:49:03 +0000 Not sure if I’m missing the point … but here is a package that appears to do the job (cut down for legibility)

It uses the string global g_bidon to return a value. The disadvantage is that the value is always a string. But I suppose that functions could be added to cater for other data types.


g_bidon VARCHAR2(32767) := NULL;

— lang code

c_lang_en CONSTANT languages.language_code%TYPE := ‘EN';
c_lang_fr CONSTANT languages.language_code%TYPE := ‘FR';
c_lang_es CONSTANT languages.language_code%TYPE := ‘ES';

— Functions

FUNCTION getConstant (p_constant_name IN VARCHAR2 DEFAULT NULL)

END myConst;


FUNCTION getConstant (p_constant_name IN VARCHAR2 DEFAULT NULL)
v_return VARCHAR2(2000);
EXECUTE IMMEDIATE ‘BEGIN myConst.g_bidon := myConst.’||p_constant_name||'; END; ‘;
RETURN g_bidon;
END getConstant;

END myConst;

By: Marco Gralike Wed, 24 May 2006 21:25:12 +0000 alter table … cache;

By: Andre Crone Tue, 23 May 2006 10:30:08 +0000 @Mr Ed.
Steve Adams mentioned singe table hash clusters, I didnt.

I didn’t write the original code. This function would have never existed if it was up to me.

We have a webapplication with short living sessions. Memory is not possible for us.

By: Alex Gorbachev Tue, 23 May 2006 09:29:29 +0000 Hehe, I wrote the comment above yesterday and it was stuck in my browser until today morning when I clicked submit. Now there are enough suggestions already but point about SQL injection is still valid. :)

By: Alex Gorbachev Tue, 23 May 2006 09:25:50 +0000 Thanks for sharing this real life experience. Few comments that might help to improve it further.

Both old and new solutions have another problem that is not mentioned here. It’s very insecure – anyone having access to this function is able to ruin the whole aplication assuming that owner is able to perform DML or DDLs on objects. Since you have big application – you never know where it exposed and who gets access to the function.

With redesign you have introduced another problem. Though less significant than hard parse – it’s many selects of same row or rows in the same block. You can avoid it with PL/SQL tables that would cache values for the session.

Another disadvantage of both solutions is the package itself – anytime you change the constant you are at risk to make a mistake rendering the package status invalid and the whole application unable to read it. In the newer solution this risk is mitigated because chances are that value is cached into the table but there still can be misses.

After all that I would question if you really need package constants anymore. Isn’t having one single lookup table accessed via single function enough? This would solve all problems. If there contention issues arise than you can consider caching values in PL/SQL table (PL/SQL table is store in PGA for each session so no contention). The only reason to keep package can be that these constants are accessed from PL/SQL blocks much more often than via function now.

By: Olof Tue, 23 May 2006 08:09:44 +0000 Why your fonction uses ‘execute_immediate’ ? Why not a simple ‘return my_name;’ ???

By: karl Mon, 22 May 2006 22:47:21 +0000 @Francois
Paramter could be numeric or string so an additionally pl/sql collection as described would be fine to store the vals all to strings like the Environment in the korn shell.
Youd could even mark the type of the parameter.

By: Wilfred Mon, 22 May 2006 22:21:56 +0000 We had exactly the same problem. I did not use a database table, but the forementioned PL/SQL table. Especially when using the function in a SQL statement it might be executed hundreds or thousands of times for getting the same constant.

Two things we did:
1) make the function DETERMINISTIC. Oracle 10gR2 “caches” the result and only executes the function once for a SQL statement, even if the constant is required in something like a nested loop.
2) The get_constant function first checks in a package variable (PL/SQL table) if the constant is in that table. Initially the table is just empty. If the constant is in the table, return that value. If it’s not in the table, query it using dynamic SQL and store it in the PL/SQL table before returning the value. This bascially implements a PL/SQL caching table in memory.
This way you don’t run the risk of an outdated database “cache” table. The caching is all done in a package (“session”) variable. We found that the get_constant function is only performing the actual dynamic SQL a couple of times for a session since most of the get_constant calls tend to be for the same set of constants.

PS. You can use this PL/SQL caching table trick for all sorts of functions that you expect to be called multiple times with the same parameters.

It would be even better if you can have some sort of memory structure shared by all sessions to do the in-memory caching. This way all sessions benefit from a single session adding something to the cache. I cannot think of a way to do this in PL/SQL. Perhaps something with Java or an external process. (or would that be too much overhead)

By: harm Mon, 22 May 2006 22:16:18 +0000 Hi Andre,
Your ‘get_my_constant’ function enables SQL injection. Bad.

By: Francois Degrelle Mon, 22 May 2006 19:47:18 +0000 Because you use a table to store the values, you could initialize your package constants with the values of this table.
It would not be a big job.

By: Mr. Ed Mon, 22 May 2006 19:40:06 +0000 What, Steve Adams didn’t mention single-table hash clusters? Shocking.

If the number of constants is low, a simple set of “if” statements might be faster:

if p_constant = “foo” then

end if;

Also, if you used PLSQL arrays, you don’t have to rewrite the constants package. Instead of using a table as a “cache”, you use the PLSQL arrays as a “cache”.

By: Andre Crone Mon, 22 May 2006 18:00:37 +0000 @Karl:
I just have written a document here at the project describing how we could use context with our own namespaces. Yes they would greatly reduce the need for this package. And about the LIO’s. We now have two queries generating more LIO’s than my function call. I love statspack!!!! I will write a post about those two queries very soon. I just have to test my final results on a server on which I can be the DBA (that’s at home).

That would be my ideal solution; but I would have to test it. But again I decided not to do so, because it would mean a complete rewrite of a very important package.

By: Francois Mon, 22 May 2006 17:47:58 +0000 Nice tip.

Another kind of approach using a PL/SQL table:


tab_values TYP_TAB_NUMBER ;

FUNCTION Get_Value( PC$ParamName IN VARCHAR2 )

END Pkg_Constants;


FUNCTION Get_Value( PC$ParamName IN VARCHAR2 )
RETURN tab_values( PC$ParamName ) ;

— initialisation phase —
tab_values( ‘param1′ ) := 1.0 ;
tab_values( ‘param5′ ) := 5.0 ;
tab_values( ‘param10′ ) := 10.0 ;

END Pkg_Constants;

SQL> select PKG_CONSTANTS.Get_Value(‘param10′) from dual
2 /