Java UDF Questions re scratchpads

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Rhino

    Java UDF Questions re scratchpads

    I've been playing with Java UDFs for the last couple of days and I've got
    some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.

    Somewhere in the manuals, I found some remarks that said I could either
    manage my scratchpad with the getScratchpad() and setScratchpad() methods
    *OR* set up my own class variables to keep the state between invocations of
    the UDF. (I can't find those remarks again right now but I know I saw them.)
    I proved that those remarks were correct by developing two successful
    variants of the same simple UDF. The code is appended below.

    My question is, having tried writing both, why would anyone use
    getScratchpad() and setScratchpad() when it is so much easier to just write
    each value that needs to be saved to a class variable? The latter approach
    is easier and much more concise since you don't have to set up and read the
    byte streams that are required to work with getScratchpad() and
    setScratchpad() .

    Still, I know that the developers at IBM are not fools so I assume there are
    some genuine benefits to use getScratchpad() and setScratchpad() or some
    major risks or limitations to just using class variables so I would be very
    interested in hearing more about those risks and benefits. That would help
    me choose the best coding style for UDFs.

    Here is the code I wrote contrasting the two approaches to scratchpads so
    that everyone can see the differences in the size of the two methods. This
    code was written using the DB2GENERAL parameter style since the JAVA
    parameter style doesn't support scratchpads.

    ----------------------------------------------------------------------------
    ---------------------
    public class CountRows extends UDF {

    /**
    * The scratchpad for the numberLines() method. It *must* be initialized
    outside of
    * the method.
    */
    private int lineCounter = 0;

    /**
    * The row counter for the numberRows() method. It *must* be initialized
    outside of
    * the method.
    */
    private int rowCounter = 0;

    /** The scratchpad buffer for the numberRows() method. */
    private byte[] scratchpadBuffe r;


    /**
    * Method numberLines() is used to number the lines of a result set.
    *
    * <p>This method accomplishes the same result as the numberRows()
    method elsewhere
    * in this class but uses a class variable instead of the
    'getScratchpad( )' and
    * 'setScratchpad( )' methods so that developers can make an informed
    comparison
    * between the two approaches.</p>
    *
    * @return int the current number of lines in the result set
    * @throws Exception
    */
    public void numberLines(int lineCount) throws Exception {

    String METHOD_NAME = "numberLines()" ;

    try {

    /*
    * Increment the line counter. The counter starts at 0 and
    increments once for each
    * row in the result set of the query. Therefore, the lines of
    the result set will be
    * numbered 1, 2, 3, etc.
    */
    lineCounter++;

    /* Return the value of the line counter. */
    set(1, lineCounter);
    } catch (Exception excp) {
    excp.printStack Trace();
    throw new IllegalArgument Exception("coun tRows() - " +
    excp.getMessage ());
    }
    }


    /**
    * Method numberRows() is used to number the rows of a result set.
    *
    * <p>This method accomplishes the same result as the numberLines()
    method elsewhere
    * in this class but uses the 'getScratchpad( )' and 'setScratchpad( )'
    methods
    * instead of a class variable so that developers can make an informed
    comparison
    * between the two approaches.</p>
    *
    * @return int the current number of rows in the result set
    * @throws Exception
    */
    public void numberRows(int lineCount) throws Exception {

    String METHOD_NAME = "numberRows ()";

    try {
    /* Initialize the scratchpad buffer. */
    scratchpadBuffe r = getScratchpad() ;

    /* Read the contents of the DB2 scratchpad. */
    ByteArrayInputS tream byteArrayInputS tream = new
    ByteArrayInputS tream(scratchpa dBuffer);
    DataInputStream dataInputStream = new
    DataInputStream (byteArrayInput Stream);

    /* Write a byte stream containing the initial value of the row
    counter, which is 0. */
    ByteArrayOutput Stream byteArrayOutput Stream = new
    ByteArrayOutput Stream();
    DataOutputStrea m dataOutputStrea m = new
    DataOutputStrea m(byteArrayOutp utStream);
    dataOutputStrea m.writeInt(rowC ounter);

    /*
    * Copy the byte stream to a byte array. Copy that byte array to
    *another* byte array.
    * Set the DB2 scratchpad equal to the second byte array.
    */
    byte[] byteArrayBuffer = byteArrayOutput Stream.toByteAr ray();
    for(int ix = 0; ix < byteArrayBuffer .length; ix++) {
    scratchpadBuffe r[ix] = byteArrayBuffer[ix];
    }
    setScratchpad(s cratchpadBuffer );

    /* Get the DB2 scratchpad and parse it to get the current value
    of the row counter. */
    byte[] scratchpadBuffe r = getScratchpad() ;
    rowCounter = dataInputStream .readInt();

    /*
    * Increment the line counter. The counter starts at 0 and
    increments once for each
    * row in the result set of the query. Therefore, the lines of
    the result set will
    * be numbered 1, 2, 3, etc.
    */
    rowCounter++;

    /* Return the value of the row counter. */
    set(1, rowCounter);
    } catch (IOException excp) {
    excp.printStack Trace();
    throw new IllegalArgument Exception("numb erRows() - " +
    excp.getMessage ());
    } catch (Exception excp) {
    excp.printStack Trace();
    throw new IllegalArgument Exception("numb erRows() - " +
    excp.getMessage ());
    }
    }
    }
    ----------------------------------------------------------------------------
    ---------------------


    --
    Rhino


  • Rob Wilson

    #2
    Re: Java UDF Questions re scratchpads

    Rhino wrote:
    [color=blue]
    > I've been playing with Java UDFs for the last couple of days and I've got
    > some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.
    >
    > Somewhere in the manuals, I found some remarks that said I could either
    > manage my scratchpad with the getScratchpad() and setScratchpad() methods
    > *OR* set up my own class variables to keep the state between invocations of
    > the UDF. (I can't find those remarks again right now but I know I saw them.)
    > I proved that those remarks were correct by developing two successful
    > variants of the same simple UDF. The code is appended below.
    >
    > My question is, having tried writing both, why would anyone use
    > getScratchpad() and setScratchpad() when it is so much easier to just write
    > each value that needs to be saved to a class variable? The latter approach
    > is easier and much more concise since you don't have to set up and read the
    > byte streams that are required to work with getScratchpad() and
    > setScratchpad() .
    >
    > Still, I know that the developers at IBM are not fools so I assume there are
    > some genuine benefits to use getScratchpad() and setScratchpad() or some
    > major risks or limitations to just using class variables so I would be very
    > interested in hearing more about those risks and benefits. That would help
    > me choose the best coding style for UDFs.
    >[/color]

    I wrote a (table) UDF that connected to a remote thingy, performed an
    operation, and would get back a set of results. I would retrieve all
    the results, stick them on my scratchpad, and disconnect in the init
    phase. In the row-returning phase (I don't have the code or a manual
    nearby, unfortunately) I would simply pull a row off the scratchpad and
    return it.

    I do not know how easy this would be with a class variable, I come from
    a C background and the scratchpad made a lot of sense at the time.

    --
    Rob Wilson

    Comment

    • amurchis

      #3
      Re: Java UDF Questions re scratchpads

      I really can't think of any REAL reason why you'd use the scratchpad
      method instead of a class variable.

      The scratchpad is a holdover from C UDFs, where there was no nice object
      structure to work with; there were just functions on a library, so DB2
      needed a mechansim for UDFs to pass information from one invocation to
      the next within the same query. This style of information passing was
      simply preserved for parameter style DB2GENERAL -- probably so that
      developers used to coding procedure-style C routines could somewhat
      comfortably adjust to coding in object-oriented JAVA without having to
      learn new concepts.

      However, DB2GENERAL will actually create an object instance behind the
      scenes for each instance of the UDF in a given query and invoke that
      specified member function of that object. Therefore, you can due to the
      object oriented nature of that parameter style just create a member
      variable of the class, and initialize it in the constructor of your UDF
      class and set that instead it will work just fine.

      However, using the scratchpad absolutely GAURANTEES that within the same
      query, the information in the scratchpad will travel from one invocation
      of the method to the next as is, without being altered from what it was
      set to. If instead you store your data as a member object inside your
      class, DB2 does not "know" about that member variable and cannot
      directly maintain it -- that's controlled by JAVA and the fact that DB2
      uses the same object from UDF invocation to invocation within the same
      query.

      In THEORY, however, DB2 might decide that it needs to discard it's
      current object and build an new one to continue the query. I this case,
      DB2 could easily still preserve the scratchpad for this new object,
      but any information in the old object -- of which DB2 has no information
      -- would be lost.

      That being said, though, any instances where DB2 could POTENTIALLY want
      to use a new object instance -- and there are none now that I know of --
      should be severe enough to warrant failing the entire statement anyway.

      Of course, I obviously cannot predict all the possibilities there either.

      NOTE: you CAN NOT use static members of a class to pass information
      between different UDF methods inside the same class, or to the NEXT
      query that contains the UDF. There is absolutely no gaurentee at all
      that that information will persist, or even that different invocations
      of the UDF will be inside the same process. I just figured it was
      extremely important to mention this.

      I hope that helps.

      amurchis

      **
      Disclaimer:
      The opinions expressed above are my own and do not necessarily reflect
      the business opinion of IBM
      **

      Rhino wrote:[color=blue]
      > I've been playing with Java UDFs for the last couple of days and I've got
      > some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.
      >
      > Somewhere in the manuals, I found some remarks that said I could either
      > manage my scratchpad with the getScratchpad() and setScratchpad() methods
      > *OR* set up my own class variables to keep the state between invocations of
      > the UDF. (I can't find those remarks again right now but I know I saw them.)
      > I proved that those remarks were correct by developing two successful
      > variants of the same simple UDF. The code is appended below.
      >
      > My question is, having tried writing both, why would anyone use
      > getScratchpad() and setScratchpad() when it is so much easier to just write
      > each value that needs to be saved to a class variable? The latter approach
      > is easier and much more concise since you don't have to set up and read the
      > byte streams that are required to work with getScratchpad() and
      > setScratchpad() .
      >
      > Still, I know that the developers at IBM are not fools so I assume there are
      > some genuine benefits to use getScratchpad() and setScratchpad() or some
      > major risks or limitations to just using class variables so I would be very
      > interested in hearing more about those risks and benefits. That would help
      > me choose the best coding style for UDFs.
      >
      > Here is the code I wrote contrasting the two approaches to scratchpads so
      > that everyone can see the differences in the size of the two methods. This
      > code was written using the DB2GENERAL parameter style since the JAVA
      > parameter style doesn't support scratchpads.
      >
      > ----------------------------------------------------------------------------
      > ---------------------
      > public class CountRows extends UDF {
      >
      > /**
      > * The scratchpad for the numberLines() method. It *must* be initialized
      > outside of
      > * the method.
      > */
      > private int lineCounter = 0;
      >
      > /**
      > * The row counter for the numberRows() method. It *must* be initialized
      > outside of
      > * the method.
      > */
      > private int rowCounter = 0;
      >
      > /** The scratchpad buffer for the numberRows() method. */
      > private byte[] scratchpadBuffe r;
      >
      >
      > /**
      > * Method numberLines() is used to number the lines of a result set.
      > *
      > * <p>This method accomplishes the same result as the numberRows()
      > method elsewhere
      > * in this class but uses a class variable instead of the
      > 'getScratchpad( )' and
      > * 'setScratchpad( )' methods so that developers can make an informed
      > comparison
      > * between the two approaches.</p>
      > *
      > * @return int the current number of lines in the result set
      > * @throws Exception
      > */
      > public void numberLines(int lineCount) throws Exception {
      >
      > String METHOD_NAME = "numberLines()" ;
      >
      > try {
      >
      > /*
      > * Increment the line counter. The counter starts at 0 and
      > increments once for each
      > * row in the result set of the query. Therefore, the lines of
      > the result set will be
      > * numbered 1, 2, 3, etc.
      > */
      > lineCounter++;
      >
      > /* Return the value of the line counter. */
      > set(1, lineCounter);
      > } catch (Exception excp) {
      > excp.printStack Trace();
      > throw new IllegalArgument Exception("coun tRows() - " +
      > excp.getMessage ());
      > }
      > }
      >
      >
      > /**
      > * Method numberRows() is used to number the rows of a result set.
      > *
      > * <p>This method accomplishes the same result as the numberLines()
      > method elsewhere
      > * in this class but uses the 'getScratchpad( )' and 'setScratchpad( )'
      > methods
      > * instead of a class variable so that developers can make an informed
      > comparison
      > * between the two approaches.</p>
      > *
      > * @return int the current number of rows in the result set
      > * @throws Exception
      > */
      > public void numberRows(int lineCount) throws Exception {
      >
      > String METHOD_NAME = "numberRows ()";
      >
      > try {
      > /* Initialize the scratchpad buffer. */
      > scratchpadBuffe r = getScratchpad() ;
      >
      > /* Read the contents of the DB2 scratchpad. */
      > ByteArrayInputS tream byteArrayInputS tream = new
      > ByteArrayInputS tream(scratchpa dBuffer);
      > DataInputStream dataInputStream = new
      > DataInputStream (byteArrayInput Stream);
      >
      > /* Write a byte stream containing the initial value of the row
      > counter, which is 0. */
      > ByteArrayOutput Stream byteArrayOutput Stream = new
      > ByteArrayOutput Stream();
      > DataOutputStrea m dataOutputStrea m = new
      > DataOutputStrea m(byteArrayOutp utStream);
      > dataOutputStrea m.writeInt(rowC ounter);
      >
      > /*
      > * Copy the byte stream to a byte array. Copy that byte array to
      > *another* byte array.
      > * Set the DB2 scratchpad equal to the second byte array.
      > */
      > byte[] byteArrayBuffer = byteArrayOutput Stream.toByteAr ray();
      > for(int ix = 0; ix < byteArrayBuffer .length; ix++) {
      > scratchpadBuffe r[ix] = byteArrayBuffer[ix];
      > }
      > setScratchpad(s cratchpadBuffer );
      >
      > /* Get the DB2 scratchpad and parse it to get the current value
      > of the row counter. */
      > byte[] scratchpadBuffe r = getScratchpad() ;
      > rowCounter = dataInputStream .readInt();
      >
      > /*
      > * Increment the line counter. The counter starts at 0 and
      > increments once for each
      > * row in the result set of the query. Therefore, the lines of
      > the result set will
      > * be numbered 1, 2, 3, etc.
      > */
      > rowCounter++;
      >
      > /* Return the value of the row counter. */
      > set(1, rowCounter);
      > } catch (IOException excp) {
      > excp.printStack Trace();
      > throw new IllegalArgument Exception("numb erRows() - " +
      > excp.getMessage ());
      > } catch (Exception excp) {
      > excp.printStack Trace();
      > throw new IllegalArgument Exception("numb erRows() - " +
      > excp.getMessage ());
      > }
      > }
      > }
      > ----------------------------------------------------------------------------
      > ---------------------
      >
      >[/color]

      Comment

      • amurchis

        #4
        Re: Java UDF Questions re scratchpads

        To do this using a member variable (rough coding, just so you get the
        idea) --

        class MyUDF extends UDF
        {
        ResultSetClass externalRes = null;
        // External connection object if necessary

        public void MyTableFunction (...)
        {
        switch(getCallT ype())
        {
        case SQLUDF_TF_OPEN:
        {
        // Open your remote connection
        externalRes = // whatever command you use
        // Close connection -- maybe keep it around
        // as another member if that would close your
        // result set
        break;
        }
        case SQLUDF_TF_FETCH :
        {
        // If there are still results
        if(externalRes. Read())
        {
        // Set the results values into the return values of the UDF
        }
        else
        {
        setSQLstate("02 000");
        }
        break;
        }
        case SQLUDF_TF_CLOSE :
        {
        if (externalRes != null)
        {
        externalRes.clo se();
        externalRes = null;
        }
        // Similar for external connection if necessary
        break;
        }
        default:
        // nothing -- we're not using FIRST or FINAL call
        break;
        }
        }
        }

        Of course, you may not WANT to have that external resource connection
        open all the time while you're processing the data if you need it open
        to maintain your result object. However, even if that WAS the case, you
        could still read your result data into some kind of local member
        object anyway instead of into the scratchpad.


        Rob Wilson wrote:
        [color=blue]
        >
        > I wrote a (table) UDF that connected to a remote thingy, performed an
        > operation, and would get back a set of results. I would retrieve all
        > the results, stick them on my scratchpad, and disconnect in the init
        > phase. In the row-returning phase (I don't have the code or a manual
        > nearby, unfortunately) I would simply pull a row off the scratchpad and
        > return it.
        >
        > I do not know how easy this would be with a class variable, I come from
        > a C background and the scratchpad made a lot of sense at the time.
        >[/color]

        Comment

        • Rhino

          #5
          Re: Java UDF Questions re scratchpads

          Thanks for your reply to my question!

          I was just wondering if there was a big "gotcha" waiting for me if I relied
          on class variables instead of getScratchpad()/setScratchpad() . It sounds
          like I *should* be safe using class variables but not as if you are actually
          certain that there will never be a case where I will regret it ;-)

          I see from your email address that you are an IBMer. I hope this isn't nosy
          or rude or anything but do you work on the DB2 team at the Toronto lab in
          some capacity or are you in some other department? I'm just curious whether
          you have "inside" knowledge or if you are just a "regular user" like me? I'm
          not going to hold you to anything you say or sue IBM if it turns out to be
          incorrect; I'm just trying to understand how much you actually know about
          the internals of DB2 and its Java support and how much you're just inferring
          from the manuals and your own experience.

          Rhino

          "amurchis" <amurchis@ca.ib m.com> wrote in message
          news:4238c5ba_4 @news3.prserv.n et...[color=blue]
          > I really can't think of any REAL reason why you'd use the scratchpad
          > method instead of a class variable.
          >
          > The scratchpad is a holdover from C UDFs, where there was no nice object
          > structure to work with; there were just functions on a library, so DB2
          > needed a mechansim for UDFs to pass information from one invocation to
          > the next within the same query. This style of information passing was
          > simply preserved for parameter style DB2GENERAL -- probably so that
          > developers used to coding procedure-style C routines could somewhat
          > comfortably adjust to coding in object-oriented JAVA without having to
          > learn new concepts.
          >
          > However, DB2GENERAL will actually create an object instance behind the
          > scenes for each instance of the UDF in a given query and invoke that
          > specified member function of that object. Therefore, you can due to the
          > object oriented nature of that parameter style just create a member
          > variable of the class, and initialize it in the constructor of your UDF
          > class and set that instead it will work just fine.
          >
          > However, using the scratchpad absolutely GAURANTEES that within the same
          > query, the information in the scratchpad will travel from one invocation
          > of the method to the next as is, without being altered from what it was
          > set to. If instead you store your data as a member object inside your
          > class, DB2 does not "know" about that member variable and cannot
          > directly maintain it -- that's controlled by JAVA and the fact that DB2
          > uses the same object from UDF invocation to invocation within the same
          > query.
          >
          > In THEORY, however, DB2 might decide that it needs to discard it's
          > current object and build an new one to continue the query. I this case,
          > DB2 could easily still preserve the scratchpad for this new object,
          > but any information in the old object -- of which DB2 has no information
          > -- would be lost.
          >
          > That being said, though, any instances where DB2 could POTENTIALLY want
          > to use a new object instance -- and there are none now that I know of --
          > should be severe enough to warrant failing the entire statement anyway.
          >
          > Of course, I obviously cannot predict all the possibilities there either.
          >
          > NOTE: you CAN NOT use static members of a class to pass information
          > between different UDF methods inside the same class, or to the NEXT
          > query that contains the UDF. There is absolutely no gaurentee at all
          > that that information will persist, or even that different invocations
          > of the UDF will be inside the same process. I just figured it was
          > extremely important to mention this.
          >
          > I hope that helps.
          >
          > amurchis
          >
          > **
          > Disclaimer:
          > The opinions expressed above are my own and do not necessarily reflect
          > the business opinion of IBM
          > **
          >
          > Rhino wrote:[color=green]
          > > I've been playing with Java UDFs for the last couple of days and I've[/color][/color]
          got[color=blue][color=green]
          > > some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.
          > >
          > > Somewhere in the manuals, I found some remarks that said I could either
          > > manage my scratchpad with the getScratchpad() and setScratchpad()[/color][/color]
          methods[color=blue][color=green]
          > > *OR* set up my own class variables to keep the state between invocations[/color][/color]
          of[color=blue][color=green]
          > > the UDF. (I can't find those remarks again right now but I know I saw[/color][/color]
          them.)[color=blue][color=green]
          > > I proved that those remarks were correct by developing two successful
          > > variants of the same simple UDF. The code is appended below.
          > >
          > > My question is, having tried writing both, why would anyone use
          > > getScratchpad() and setScratchpad() when it is so much easier to just[/color][/color]
          write[color=blue][color=green]
          > > each value that needs to be saved to a class variable? The latter[/color][/color]
          approach[color=blue][color=green]
          > > is easier and much more concise since you don't have to set up and read[/color][/color]
          the[color=blue][color=green]
          > > byte streams that are required to work with getScratchpad() and
          > > setScratchpad() .
          > >
          > > Still, I know that the developers at IBM are not fools so I assume there[/color][/color]
          are[color=blue][color=green]
          > > some genuine benefits to use getScratchpad() and setScratchpad() or some
          > > major risks or limitations to just using class variables so I would be[/color][/color]
          very[color=blue][color=green]
          > > interested in hearing more about those risks and benefits. That would[/color][/color]
          help[color=blue][color=green]
          > > me choose the best coding style for UDFs.
          > >
          > > Here is the code I wrote contrasting the two approaches to scratchpads[/color][/color]
          so[color=blue][color=green]
          > > that everyone can see the differences in the size of the two methods.[/color][/color]
          This[color=blue][color=green]
          > > code was written using the DB2GENERAL parameter style since the JAVA
          > > parameter style doesn't support scratchpads.
          > >[/color]
          >
          > --------------------------------------------------------------------------[/color]
          --[color=blue][color=green]
          > > ---------------------
          > > public class CountRows extends UDF {
          > >
          > > /**
          > > * The scratchpad for the numberLines() method. It *must* be[/color][/color]
          initialized[color=blue][color=green]
          > > outside of
          > > * the method.
          > > */
          > > private int lineCounter = 0;
          > >
          > > /**
          > > * The row counter for the numberRows() method. It *must* be[/color][/color]
          initialized[color=blue][color=green]
          > > outside of
          > > * the method.
          > > */
          > > private int rowCounter = 0;
          > >
          > > /** The scratchpad buffer for the numberRows() method. */
          > > private byte[] scratchpadBuffe r;
          > >
          > >
          > > /**
          > > * Method numberLines() is used to number the lines of a result set.
          > > *
          > > * <p>This method accomplishes the same result as the numberRows()
          > > method elsewhere
          > > * in this class but uses a class variable instead of the
          > > 'getScratchpad( )' and
          > > * 'setScratchpad( )' methods so that developers can make an informed
          > > comparison
          > > * between the two approaches.</p>
          > > *
          > > * @return int the current number of lines in the result set
          > > * @throws Exception
          > > */
          > > public void numberLines(int lineCount) throws Exception {
          > >
          > > String METHOD_NAME = "numberLines()" ;
          > >
          > > try {
          > >
          > > /*
          > > * Increment the line counter. The counter starts at 0 and
          > > increments once for each
          > > * row in the result set of the query. Therefore, the lines[/color][/color]
          of[color=blue][color=green]
          > > the result set will be
          > > * numbered 1, 2, 3, etc.
          > > */
          > > lineCounter++;
          > >
          > > /* Return the value of the line counter. */
          > > set(1, lineCounter);
          > > } catch (Exception excp) {
          > > excp.printStack Trace();
          > > throw new IllegalArgument Exception("coun tRows() - " +
          > > excp.getMessage ());
          > > }
          > > }
          > >
          > >
          > > /**
          > > * Method numberRows() is used to number the rows of a result set.
          > > *
          > > * <p>This method accomplishes the same result as the numberLines()
          > > method elsewhere
          > > * in this class but uses the 'getScratchpad( )' and[/color][/color]
          'setScratchpad( )'[color=blue][color=green]
          > > methods
          > > * instead of a class variable so that developers can make an[/color][/color]
          informed[color=blue][color=green]
          > > comparison
          > > * between the two approaches.</p>
          > > *
          > > * @return int the current number of rows in the result set
          > > * @throws Exception
          > > */
          > > public void numberRows(int lineCount) throws Exception {
          > >
          > > String METHOD_NAME = "numberRows ()";
          > >
          > > try {
          > > /* Initialize the scratchpad buffer. */
          > > scratchpadBuffe r = getScratchpad() ;
          > >
          > > /* Read the contents of the DB2 scratchpad. */
          > > ByteArrayInputS tream byteArrayInputS tream = new
          > > ByteArrayInputS tream(scratchpa dBuffer);
          > > DataInputStream dataInputStream = new
          > > DataInputStream (byteArrayInput Stream);
          > >
          > > /* Write a byte stream containing the initial value of the[/color][/color]
          row[color=blue][color=green]
          > > counter, which is 0. */
          > > ByteArrayOutput Stream byteArrayOutput Stream = new
          > > ByteArrayOutput Stream();
          > > DataOutputStrea m dataOutputStrea m = new
          > > DataOutputStrea m(byteArrayOutp utStream);
          > > dataOutputStrea m.writeInt(rowC ounter);
          > >
          > > /*
          > > * Copy the byte stream to a byte array. Copy that byte[/color][/color]
          array to[color=blue][color=green]
          > > *another* byte array.
          > > * Set the DB2 scratchpad equal to the second byte array.
          > > */
          > > byte[] byteArrayBuffer =[/color][/color]
          byteArrayOutput Stream.toByteAr ray();[color=blue][color=green]
          > > for(int ix = 0; ix < byteArrayBuffer .length; ix++) {
          > > scratchpadBuffe r[ix] = byteArrayBuffer[ix];
          > > }
          > > setScratchpad(s cratchpadBuffer );
          > >
          > > /* Get the DB2 scratchpad and parse it to get the current[/color][/color]
          value[color=blue][color=green]
          > > of the row counter. */
          > > byte[] scratchpadBuffe r = getScratchpad() ;
          > > rowCounter = dataInputStream .readInt();
          > >
          > > /*
          > > * Increment the line counter. The counter starts at 0 and
          > > increments once for each
          > > * row in the result set of the query. Therefore, the lines[/color][/color]
          of[color=blue][color=green]
          > > the result set will
          > > * be numbered 1, 2, 3, etc.
          > > */
          > > rowCounter++;
          > >
          > > /* Return the value of the row counter. */
          > > set(1, rowCounter);
          > > } catch (IOException excp) {
          > > excp.printStack Trace();
          > > throw new IllegalArgument Exception("numb erRows() - " +
          > > excp.getMessage ());
          > > } catch (Exception excp) {
          > > excp.printStack Trace();
          > > throw new IllegalArgument Exception("numb erRows() - " +
          > > excp.getMessage ());
          > > }
          > > }
          > > }[/color]
          >
          > --------------------------------------------------------------------------[/color]
          --[color=blue][color=green]
          > > ---------------------
          > >
          > >[/color][/color]


          Comment

          Working...