Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
Database Servers
DB2InformixIngresMS SQLOraclePervasive.SQLPostgreSQLProgressSybase
Desktop Databases
FileMakerFoxProMS AccessParadox
General
General DB TopicsDatabase Theory
Related Topics
Java Development.NET DevelopmentVB DevelopmentMore Topics ...

Database Forum / DB2 Topics / March 2005

Tip: Looking for answers? Try searching our database.

UDF Design Question

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Rhino - 02 Mar 2005 17:21 GMT
Since I haven't been able to find out yet how to get my Eclipse debugger to
step through my Java UDF code, I am adding old-style File I/O debugging to
some of my UDFs. I'm not sure of the best way to design this though and am
looking for some suggestions.

Since my class might contain several UDF methods, for instance, several
versions of the same basic UDF but with different signatures for different
situations, e.g. count(needle, haystack), count(needle, haystack, start),
and count(needle, haystack, start, finish), any or all of which might want
to do logging, I've decided to create separate methods for each of the
following tasks: create/open the log file; write to the log file; close the
log file.

Now, what should I do if one of the methods that works with the log throws
an exception? I'm trying to figure out if it is best to display an error
message and stacktrace on the console and then do a System.exit() or if
there is a better approach? I'm not clear on what behaviour DB2 wants in
this case but I'd like to give as clear and specific message as I can about
the problem. In other words, I'd much rather see this when I run the query:

   UDF count(needle, haystack, 7) failed; log file could not be opened due
to security violation

than this

   UDF failed.

Could any of you Java UDF experts please share your experience on this
point?

Signature

Rhino
---
rhino1 AT sympatico DOT ca
"There are two ways of constructing a software design. One way is to make it
so simple that there are obviously no deficiencies. And the other way is to
make it so complicated that there are no obvious deficiencies." - C.A.R.
Hoare

amurchis - 02 Mar 2005 22:01 GMT
I don't believe there's a way to debug a JAVA UDF in DB2... procedures,
yes.  I believe that support is in development, though I can't say when
it will be released.  There is a chance the Stored Procedure Debugger
MIGHT work for JAVA UDFs similar to how to works for JAVA procedures,
but I doubt it and I'm unfamiliar with that tool.

Do NOT use any System.exit() or similar calls inside a UDF or procedure
(collectively "routines").  This will bring down the process and may
cause unexpected errors/hangs in DB2 processing -- the DB2 documentation
specifically FORBIDS calling any type of exit() call inside a routine.
If your routine simply throws an exception that you do not handle (or
handle and then throw again), your client will receive a -4302 SQLCODE
error, which is probably the best behaviour to have in this case.  The
stack traceback associated with the exception will be written to the
db2diag.log, and you should be able to determine from that stack
traceback what function you were executing when the exception occured.
In other words, DON'T catch any exceptions caused by writing to your
diagnostic file; just let DB2 handle it and it should write the
information you require to the db2diag.log automatically.

Cheers!

amurchis

> Since I haven't been able to find out yet how to get my Eclipse debugger to
> step through my Java UDF code, I am adding old-style File I/O debugging to
[quoted text clipped - 25 lines]
> Could any of you Java UDF experts please share your experience on this
> point?
Rhino - 02 Mar 2005 22:38 GMT
Thanks for the reply!

I've never managed to get the stored procedure debugger to work despite a
few attempts but the manual swears that debugging of UDFs *is* possible; see
my other thread from a couple of days ago. I just can't find out how to get
it to work.

Anyway, I've been using File I/O techniques to debug. Your remarks were
quite helpful in reminding me what I *should* be doing in my UDFs ;-)

I'm going to go clean up those UDFs now ;-) I just have a couple small ones
that are in the "sandbox" while I try to figure out exactly how to do
everything.

Rhino

> I don't believe there's a way to debug a JAVA UDF in DB2... procedures,
> yes.  I believe that support is in development, though I can't say when
[quoted text clipped - 49 lines]
> > Could any of you Java UDF experts please share your experience on this
> > point?
amurchis - 02 Mar 2005 23:35 GMT
Another thing you could do now that I think about it if you're coding in
PARAMETER STYLE JAVA.

Write a JAVA application that calls your UDF method DIRECTLY and passes
in different values.  So long as both are compiled in debug mode, you
should just be able to start up the application under the debugger and
have at it.

For instance (pseudocode):

public static void main(string argv[])
{
    for (i < number of times you want to execute the UDF)
    {
        value = yourclassname.yourmethodname(firstarg[i],
                        secondarg[i], ...);
        System.out.println(value);
    }
}

This is essentially what DB2 would do if you're calling the UDF within a
 SELECT query, where <number of times you ant to execute the UDF> is
the number of rows returned by the query.

However, this is useless if you're using PARAMETER STYLE DB2GENERAL due
to how the processing for that style ties back into the DB2 architecture
through the inherited UDF class.  In that case what you're doing is
probably the best way to do it.

> Thanks for the reply!
>
[quoted text clipped - 97 lines]
>>>Could any of you Java UDF experts please share your experience on this
>>>point?
amurchis - 02 Mar 2005 23:48 GMT
WARNING: This assumes you're not using any SQL inside your UDF.  If that
is the case, you'll probably need to modify your UDF to take a
connection object as the first parameter (and open the connection inside
your application).  Obviously, the "jdbc:default:connection" logic will
not work inside your application.

> Another thing you could do now that I think about it if you're coding in
> PARAMETER STYLE JAVA.
[quoted text clipped - 132 lines]
>>>> Could any of you Java UDF experts please share your experience on this
>>>> point?
Rhino - 03 Mar 2005 00:04 GMT
Hmmm, maybe I was too hasty in taking those System.exit() calls out of my
UDFs....

I was doing a System.exit() within the catch logic for each of the three
methods that work with the log file; createFile(), writeFile() and
closeFile(). Here are all three methods:

  static public BufferedWriter createFile(String path, String fileName) {

       /* Define the buffered writer. */
       BufferedWriter bufferedWriter = null;

       try {
           /*
            * See if the output directory exists; if it doesn't, create it
and
            * any needed parent directories.
            */
           File outputPath = new File(path);
           System.out.println("outputPath=" + outputPath);
           if (!outputPath.exists()) {
               outputPath.mkdirs();
           }

           /* See if the output file exists; if it doesn't, create it. */
           outputFile = new File(outputPath, fileName);
           System.out.println("outputFile=" + outputFile);
           if (!outputFile.exists()) {
               outputFile.createNewFile();
           }

           /* Create the file, indicating that we will be appending to it.
*/
           FileWriter fileWriter = new FileWriter(path + File.separator +
fileName, true);
           bufferedWriter = new BufferedWriter(fileWriter);
       } catch (SecurityException s_excp) {
           System.out.println("SecurityException encountered. Message: " +
s_excp.getMessage());
           s_excp.printStackTrace();
           System.exit(16);
       } catch (IOException io_excp) {
           System.out.println("IOException encountered. Message: " +
io_excp.getMessage());
           io_excp.printStackTrace();
           System.exit(16);
       }

       return (bufferedWriter);
   }

   static public void writeToFile(BufferedWriter outputFile, String
oneLine) {

    try {
     outputFile.write(oneLine);
     outputFile.newLine();
     }
    catch (IOException io_excp) {
     System.out.println("IOException encountered while writing line '" +
oneLine +
      "' to file " + outputFile + ".\nMessage: " + io_excp);
     io_excp.printStackTrace();
     System.exit(16);
     }

   }

   static public void closeFile(BufferedWriter outputFile) {

    try {
     outputFile.flush();
     outputFile.close();
     }
    catch (IOException io_excp) {
     System.err.println("IOException encountered while closing file " +
      outputFile + ".\nMessage: " + io_excp);
     io_excp.printStackTrace();
     System.exit(16);
     }
   }

I deliberately specified the path to the log file as being on drive Z: of my
Windows XP machine - I don't have a drive Z: - and ran the code exactly as
you see here to see how it would respond to the error. Strangely enough, it
got all the way through the createFile() method without a hiccup but crashed
on a NullPointerException in the writeFile() method; the stacktrace was
written to db2diag.log. I got an SQL4302 in the first statement that tried
to invoke the UDF. I got SQL4301 Reason Code 4 on each subsequent invocation
of the function.

When I followed your advice and removed the System.exit() calls from the
catch logic of each method, I got an SQL0440N (No such function) at each
invocation of the function. That is nonsense because I had just finished
generating the function again and got green lights on every step. Nothing
was written to db2diag.log either.

I like the behaviour of the function a LOT better when the System.exit(16)
was in each catch block!

Do you have any idea how to this is working? I'm baffled by why the
createFile() method is working and that bothers me; it should have failed.
But aside from that, I'm getting behaviour I can live with when I leave the
System.exit() in the catch blocks. The behaviour when I omit them is not
tolerable to me because it is very misleading.

Mind you, I'd prefer different behaviour altogether if I could figure out
how to get it: I'd like to get a specific message that says something like
"I/O Error in function foo(): Couldn't open log file because Drive Z: does
not exist." But If I can't get that, I'll take SQL4302 with a stacktrace in
db2diag.log over a bogus SQL0440N any time ;-)

Any ideas?

Rhino

> Thanks for the reply!
>
[quoted text clipped - 76 lines]
> > > Could any of you Java UDF experts please share your experience on this
> > > point?
Rhino - 03 Mar 2005 14:06 GMT
This is a followup to my own post in case anyone else is monitoring this
thread, either now or in the future.

I figured out why my createFile() method didn't crash. The createNewFile()
method *was* failing, causing an IOException. The IOException was handled by
my catch block but I didn't handle it correctly: I simply displayed a
message via System.out.println() and displayed the stackTrace, neither of
which ever appeared because you can't do console I/O in a UDF. Then, since
the System.exit() was not there, the method ended, returning a null for the
BufferedWriter. Since I wasn't checking to ensure that I had a non-null
BufferedWriter, the code continued until it tried to write a line to the
non-existent log, at which point the runtime NullPointerException occurred
in writeToFile(). That exception DID appear in db2diag.log.

I should have thought about this problem a bit more before asking anyone
else to explain it to me ;-)

---

I've also discovered that if I want to give the user a meaningful message
text, I can do so. In light of my new understanding of my createFile()
method's behaviour, I simply modified the code in my UDF a bit so that it
looked like this:

       log = createFile(LOG_PATH, LOG_FILE);
       if (log==null) throw new IllegalArgumentException("log file is
null");

As a result, when my log file couldn't be created because I'd specified a
non-existent Z drive, the SQL that invoked the function returned:

COM.ibm.db2.jdbc.DB2Exception: [IBM][CLI Driver][DB2/NT] SQL4302N Java
stored procedure or user-defined function "RHINO.COUNTCHAR", specific name
"COUNTCHAR2" aborted with an exception "log file is null". SQLSTATE=38501

In other words, I *can* make a meaningful message of my own choosing that
will appear if things go wrong in the UDF. This isn't a very GOOD message
yet but I know I can improve on this and get something very close to what I
had wanted.

Rhino
Knut Stolze - 07 Mar 2005 10:40 GMT
> I've also discovered that if I want to give the user a meaningful message
> text, I can do so. In light of my new understanding of my createFile()
[quoted text clipped - 11 lines]
> stored procedure or user-defined function "RHINO.COUNTCHAR", specific name
> "COUNTCHAR2" aborted with an exception "log file is null". SQLSTATE=38501

Alternatively, you could also use the "setSQLmessage" and "setSQLstatem"
methods and set your own error message that way.  You just have to be awary
that the message must not be longer than 70 bytes.

Signature

Knut Stolze
Information Integration
IBM Germany / University of Jena

 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.