In my database interfacing library jOOQ, I would like to add support for Oracle (or DB2, etc) packages. I have already implemented stored procedure/function support where every stored object is modelled as a generated Java class. For example, this stored function
CREATE FUNCTION f_author_exists (author_name VARCHAR2) RETURNS NUMBER;
will generate a class that can be used like this (note, there are also lots of convenience methods, this example just shows the general design):
// A new "function call instance". The function needs to be instanciated
// once per call
FAuthorExists f = new FAuthorExists();
// Set the function parameters on the call instance and call it
f.setAuthorName("Paulo");
f.execute(connection);
//开发者_开发问答 Fetch the result from the function call instance
BigDecimal result = f.getReturnValue();
The reason I chose a mapping SQL function -> Java Class is because stored procedures allow complex return values (several OUT, or IN OUT parameters) that I want to be able to fetch one by one after calling the procedure:
p.getOutParam1();
p.getOutParam2();
Now this design works fine with stored functions / procedures, where overloading is not possible. Within Oracle's (or DB2's) packages, however, I can have several functions with the same name, like
CREATE PACKAGE my_package IS
FUNCTION f_author_exists (name VARCHAR2) RETURNS NUMBER;
FUNCTION f_author_exists (name VARCHAR2, country VARCHAR2) RETURNS NUMBER;
END my_package;
When I generate a class per function (or procedure), I will have naming clashes with several FAuthorExists
Java classes. A lame solution is to add an index to the class name, such as FAuthorExists2
, FAuthorExists3
. Another lame solution is to generate some sort of hash value (or the value itself) from the parameter names/types directly into the classname, such as FAuthorExistsVARCHAR2
, FAuthorExistsVARCHAR2VARCHAR2
. Neither solution is desirable for obvious reasons.
Does anyone have a simple solution to this problem? Or maybe an Idea of a better overall design which would not produce such function name overloading issues?
Any feedback appreciated!
Your getReturnValue
function could determine at call time which overloaded function to call depending on how many input parameters have been set - but I think it will end up being simpler if you stick to something like setParam1
rather than setName
I found no other viable way to resolve this problem than using an "overload index" on generated classes. Hence, the package
CREATE PACKAGE my_package IS
FUNCTION f_author_exists (name VARCHAR2) RETURNS NUMBER;
FUNCTION f_author_exists (name VARCHAR2, country VARCHAR2) RETURNS NUMBER;
END my_package;
Will produce these classes:
public class FAuthorExists1 { /* ... */ }
public class FAuthorExists2 { /* ... */ }
Other ideas would just cause new conflicts at code-generation time, or at runtime.
UPDATE: Note, this solution seems also the only one to handle situations like this one correctly:
CREATE PACKAGE my_package IS
PROCEDURE f_author_exists (name VARCHAR2);
PROCEDURE f_author_exists (name CHAR);
PROCEDURE f_author_exists (name CHAR, country OUT VARCHAR2);
END my_package;
As it seems, this kind of overloading is possible in PL/SQL, too.
You could overcome the limitations of overloading by giving unique names for each function. This would also improve the readability of the code (that's one reason why Golang doesn't have overloading). For example f_author_name_exists, f_author_name_country_exists.
Another way, which will complicate the Java classes, is to decide at runtime that which procedure to call, based on which overloaded Java constructor was used or which setters were used.
精彩评论