Thread: jdbc bug/feature?

jdbc bug/feature?

From
Marko Štrukelj
Date:

Hello,

There is a bug (I say) or a lack of proper functionality in JDBC driver regarding batch updates.

The following code is expected to work by some library that I use and it does work with inet tds driver for M$ SQL server. It however does not work with the latest jdbc from cvs or anything older than that either.

PreparedStatements st = c.prepareStatement("insert into my_table (field1, field2) values (?, ?)");

// we have say 30 inserts to do
Iterator it = inserts.iterator();
int i=0;
while(it.hasNext()) {

        // there is a maximum batch size of 15, so we must periodically execute it
        if(i==batchMax) {
                st.executeBatch();
                i=0;

                // the problem - after this call a PreparedStatement is empty and consequtive binds fail
        }

        Object [] binds = (Object [])it.next();
        st.setString(binds[0]);
        st.setString(binds[1]);
        st.addBatch();
        i++;
}

Upon some research I discovered the problem and found a very simple solution:

In org.postgresql.jdbc2.AbstractJdbc2Statement:

        public int[] executeBatch() throws SQLException
        {
System.out.println("### executeBatch");
                if (batch == null)
                        batch = new Vector();
                int size = batch.size();
                int[] result = new int[size];
                int i = 0;

// >>> added
                // save m_binds and m_sqlFragments because executeUpdate(String) will destroy them
                String [] oldFrags = m_sqlFragments;
                Object [] oldMBinds = m_binds;
// <<

                try
                {                      
                        for (i = 0;i < size;i++)
                                result[i] = this.executeUpdate((String)batch.elementAt(i));

                }
                catch (SQLException e)
                {
                        int[] resultSucceeded = new int[i];
                        System.arraycopy(result, 0, resultSucceeded, 0, i);

                        PBatchUpdateException updex =
                                new PBatchUpdateException("postgresql.stat.batch.error",
                                                                                  new Integer(i), batch.elementAt(i), resultSucceeded);

                        updex.setNextException(e);

                        throw updex;
                }
                finally
                {
                        batch.removeAllElements();
// >> added                    
                        // restore m_binds and m_sqlFragments
                        m_sqlFragments = oldFrags;
                        m_binds = oldMBinds;
// <<
                }
                return result;
        }


Please consider this as a bug, and patch it in cvs. I did not test this very well, so the described patch may possibly cause some incosistencies somewhere - the people who wrote that class will know best. It does work for my case though.

And thanks for PostgreSQL, I've just started using it and I love it.

- Marko

Re: jdbc bug/feature?

From
Barry Lind
Date:
Marko,

I checked in a fix for this problem.  It should appear in 7.3RC2 this
weekend.

thanks,
--Barry


Marko Štrukelj wrote:
>
> Hello,
>
> There is a bug (I say) or a lack of proper functionality in JDBC driver
> regarding batch updates.
>
> The following code is expected to work by some library that I use and it
> does work with inet tds driver for M$ SQL server. It however does not
> work with the latest jdbc from cvs or anything older than that either.
>
>
> PreparedStatements st = c.prepareStatement("insert into my_table
> (field1, field2) values (?, ?)");
>
> // we have say 30 inserts to do
> Iterator it = inserts.iterator();
> int i=0;
> while(it.hasNext()) {
>
>         // there is a maximum batch size of 15, so we must periodically
> execute it
>         if(i==batchMax) {
>                 st.executeBatch();
>                 i=0;
>
>                 // the problem - after this call a PreparedStatement is
> empty and consequtive binds fail
>         }
>
>         Object [] binds = (Object [])it.next();
>         st.setString(binds[0]);
>         st.setString(binds[1]);
>         st.addBatch();
>         i++;
> }
>
>
>
> Upon some research I discovered the problem and found a very simple
> solution:
>
> In org.postgresql.jdbc2.AbstractJdbc2Statement:
>
>         public int[] executeBatch() throws SQLException
>         {
> System.out.println("### executeBatch");
>                 if (batch == null)
>                         batch = new Vector();
>                 int size = batch.size();
>                 int[] result = new int[size];
>                 int i = 0;
>
> // >>> added
>                 // save m_binds and m_sqlFragments because
> executeUpdate(String) will destroy them
>                 String [] oldFrags = m_sqlFragments;
>                 Object [] oldMBinds = m_binds;
> // <<
>
>                 try
>                 {
>                         for (i = 0;i < size;i++)
>                                 result[i] =
> this.executeUpdate((String)batch.elementAt(i));
>
>                 }
>                 catch (SQLException e)
>                 {
>                         int[] resultSucceeded = new int[i];
>                         System.arraycopy(result, 0, resultSucceeded, 0, i);
>
>                         PBatchUpdateException updex =
>                                 new
> PBatchUpdateException("postgresql.stat.batch.error",
>
>           new Integer(i), batch.elementAt(i), resultSucceeded);
>
>                         updex.setNextException(e);
>
>                         throw updex;
>                 }
>                 finally
>                 {
>                         batch.removeAllElements();
> // >> added
>                         // restore m_binds and m_sqlFragments
>                         m_sqlFragments = oldFrags;
>                         m_binds = oldMBinds;
> // <<
>                 }
>                 return result;
>         }
>
>
>
>
> Please consider this as a bug, and patch it in cvs. I did not test this
> very well, so the described patch may possibly cause some incosistencies
> somewhere - the people who wrote that class will know best. It does work
> for my case though.
>
>
> And thanks for PostgreSQL, I've just started using it and I love it.
>
>
>
> - Marko
>



Re: jdbc bug/feature?

From
Marko Štrukelj
Date:

I think the code is still buggy. Specifically:

The following lines do not restore state:

            //restore state of statement
                    String[] m_sqlFragments = l_origSqlFragments;
                        Object[] m_binds = l_origBinds;
                        String[] m_bindTypes = l_origBindTypes;

You are allocating new local variables here and you are setting them instead of inherited variables. I'm sure it's a copy-paste typo :)  Should be like this:

                    this.m_sqlFragments = l_origSqlFragments;
                        this.m_binds = l_origBinds;
                        this.m_bindTypes = l_origBindTypes;

regards,

-Marko

> -----Original Message-----
> From: Barry Lind [mailto:blind@xythos.com]
> Sent: Wednesday, November 20, 2002 9:08 AM
> To: Marko Štrukelj
> Cc: 'pgsql-jdbc@postgresql.org'
> Subject: Re: [JDBC] jdbc bug/feature?
>
>
> Marko,
>
> I checked in a fix for this problem.  It should appear in 7.3RC2 this
> weekend.
>
> thanks,
> --Barry
>
>
> Marko Štrukelj wrote:
> >
> > Hello,
> >
> > There is a bug (I say) or a lack of proper functionality in
> JDBC driver
> > regarding batch updates.
> >
> > The following code is expected to work by some library that
> I use and it
> > does work with inet tds driver for M$ SQL server. It
> however does not
> > work with the latest jdbc from cvs or anything older than
> that either.
> >
> >
> > PreparedStatements st = c.prepareStatement("insert into my_table
> > (field1, field2) values (?, ?)");
> >
> > // we have say 30 inserts to do
> > Iterator it = inserts.iterator();
> > int i=0;
> > while(it.hasNext()) {
> >
> >         // there is a maximum batch size of 15, so we must
> periodically
> > execute it
> >         if(i==batchMax) {
> >                 st.executeBatch();
> >                 i=0;
> >
> >                 // the problem - after this call a
> PreparedStatement is
> > empty and consequtive binds fail
> >         }
> >
> >         Object [] binds = (Object [])it.next();
> >         st.setString(binds[0]);
> >         st.setString(binds[1]);
> >         st.addBatch();
> >         i++;
> > }
> >
> >
> >
> > Upon some research I discovered the problem and found a very simple
> > solution:
> >
> > In org.postgresql.jdbc2.AbstractJdbc2Statement:
> >
> >         public int[] executeBatch() throws SQLException
> >         {
> > System.out.println("### executeBatch");
> >                 if (batch == null)
> >                         batch = new Vector();
> >                 int size = batch.size();
> >                 int[] result = new int[size];
> >                 int i = 0;
> >
> > // >>> added
> >                 // save m_binds and m_sqlFragments because
> > executeUpdate(String) will destroy them
> >                 String [] oldFrags = m_sqlFragments;
> >                 Object [] oldMBinds = m_binds;
> > // <<
> >
> >                 try
> >                 {                     
> >                         for (i = 0;i < size;i++)
> >                                 result[i] =
> > this.executeUpdate((String)batch.elementAt(i));
> >
> >                 }
> >                 catch (SQLException e)
> >                 {
> >                         int[] resultSucceeded = new int[i];
> >                         System.arraycopy(result, 0,
> resultSucceeded, 0, i);
> >
> >                         PBatchUpdateException updex =
> >                                 new
> > PBatchUpdateException("postgresql.stat.batch.error",
> >                                                            
>            
> >           new Integer(i), batch.elementAt(i), resultSucceeded);
> >
> >                         updex.setNextException(e);
> >
> >                         throw updex;
> >                 }
> >                 finally
> >                 {
> >                         batch.removeAllElements();
> > // >> added                   
> >                         // restore m_binds and m_sqlFragments
> >                         m_sqlFragments = oldFrags;
> >                         m_binds = oldMBinds;
> > // <<
> >                 }
> >                 return result;
> >         }
> >
> >
> >
> >
> > Please consider this as a bug, and patch it in cvs. I did
> not test this
> > very well, so the described patch may possibly cause some
> incosistencies
> > somewhere - the people who wrote that class will know best.
> It does work
> > for my case though.
> >
> >
> > And thanks for PostgreSQL, I've just started using it and I love it.
> >
> >
> >
> > - Marko
> >
>
>
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster
>

Re: jdbc bug/feature?

From
Barry Lind
Date:
Marko,

You are correct.  It was a copy-paste error.  I will fix it up today.
Thanks for the quick code review.

--Barry

Marko Štrukelj wrote:
>
> I think the code is still buggy. Specifically:
>
>
> The following lines do not restore state:
>
>             //restore state of statement
>                     String[] m_sqlFragments = l_origSqlFragments;
>                         Object[] m_binds = l_origBinds;
>                         String[] m_bindTypes = l_origBindTypes;
>
>
> You are allocating new local variables here and you are setting them
> instead of inherited variables. I'm sure it's a copy-paste typo :)
> Should be like this:
>
>                     this.m_sqlFragments = l_origSqlFragments;
>                         this.m_binds = l_origBinds;
>                         this.m_bindTypes = l_origBindTypes;
>
>
>
> regards,
>
> -Marko
>
>
>  > -----Original Message-----
>  > From: Barry Lind [mailto:blind@xythos.com]
>  > Sent: Wednesday, November 20, 2002 9:08 AM
>  > To: Marko Štrukelj
>  > Cc: 'pgsql-jdbc@postgresql.org'
>  > Subject: Re: [JDBC] jdbc bug/feature?
>  >
>  >
>  > Marko,
>  >
>  > I checked in a fix for this problem.  It should appear in 7.3RC2 this
>  > weekend.
>  >
>  > thanks,
>  > --Barry
>  >
>  >
>  > Marko Štrukelj wrote:
>  > >
>  > > Hello,
>  > >
>  > > There is a bug (I say) or a lack of proper functionality in
>  > JDBC driver
>  > > regarding batch updates.
>  > >
>  > > The following code is expected to work by some library that
>  > I use and it
>  > > does work with inet tds driver for M$ SQL server. It
>  > however does not
>  > > work with the latest jdbc from cvs or anything older than
>  > that either.
>  > >
>  > >
>  > > PreparedStatements st = c.prepareStatement("insert into my_table
>  > > (field1, field2) values (?, ?)");
>  > >
>  > > // we have say 30 inserts to do
>  > > Iterator it = inserts.iterator();
>  > > int i=0;
>  > > while(it.hasNext()) {
>  > >
>  > >         // there is a maximum batch size of 15, so we must
>  > periodically
>  > > execute it
>  > >         if(i==batchMax) {
>  > >                 st.executeBatch();
>  > >                 i=0;
>  > >
>  > >                 // the problem - after this call a
>  > PreparedStatement is
>  > > empty and consequtive binds fail
>  > >         }
>  > >
>  > >         Object [] binds = (Object [])it.next();
>  > >         st.setString(binds[0]);
>  > >         st.setString(binds[1]);
>  > >         st.addBatch();
>  > >         i++;
>  > > }
>  > >
>  > >
>  > >
>  > > Upon some research I discovered the problem and found a very simple
>  > > solution:
>  > >
>  > > In org.postgresql.jdbc2.AbstractJdbc2Statement:
>  > >
>  > >         public int[] executeBatch() throws SQLException
>  > >         {
>  > > System.out.println("### executeBatch");
>  > >                 if (batch == null)
>  > >                         batch = new Vector();
>  > >                 int size = batch.size();
>  > >                 int[] result = new int[size];
>  > >                 int i = 0;
>  > >
>  > > // >>> added
>  > >                 // save m_binds and m_sqlFragments because
>  > > executeUpdate(String) will destroy them
>  > >                 String [] oldFrags = m_sqlFragments;
>  > >                 Object [] oldMBinds = m_binds;
>  > > // <<
>  > >
>  > >                 try
>  > >                 {
>  > >                         for (i = 0;i < size;i++)
>  > >                                 result[i] =
>  > > this.executeUpdate((String)batch.elementAt(i));
>  > >
>  > >                 }
>  > >                 catch (SQLException e)
>  > >                 {
>  > >                         int[] resultSucceeded = new int[i];
>  > >                         System.arraycopy(result, 0,
>  > resultSucceeded, 0, i);
>  > >
>  > >                         PBatchUpdateException updex =
>  > >                                 new
>  > > PBatchUpdateException("postgresql.stat.batch.error",
>  > >
>  >
>  > >           new Integer(i), batch.elementAt(i), resultSucceeded);
>  > >
>  > >                         updex.setNextException(e);
>  > >
>  > >                         throw updex;
>  > >                 }
>  > >                 finally
>  > >                 {
>  > >                         batch.removeAllElements();
>  > > // >> added
>  > >                         // restore m_binds and m_sqlFragments
>  > >                         m_sqlFragments = oldFrags;
>  > >                         m_binds = oldMBinds;
>  > > // <<
>  > >                 }
>  > >                 return result;
>  > >         }
>  > >
>  > >
>  > >
>  > >
>  > > Please consider this as a bug, and patch it in cvs. I did
>  > not test this
>  > > very well, so the described patch may possibly cause some
>  > incosistencies
>  > > somewhere - the people who wrote that class will know best.
>  > It does work
>  > > for my case though.
>  > >
>  > >
>  > > And thanks for PostgreSQL, I've just started using it and I love it.
>  > >
>  > >
>  > >
>  > > - Marko
>  > >
>  >
>  >
>  >
>  > ---------------------------(end of
>  > broadcast)---------------------------
>  > TIP 4: Don't 'kill -9' the postmaster
>  >
>