Adding field to BatchUpdateException
Lance Andersen - Oracle
lance.andersen at oracle.com
Mon Nov 26 22:19:15 UTC 2012
Hi Ulf,
Thank you for the suggestion
The current spec is silent on what happens if the update count overflows for any executeUpdate method. Today the driver vendors just pass in their array of UpdateCounts (or status) to BatchException (or overflow the return count from executeUpdate) if an error occurs at some point along the way. I really would prefer to not change any existing behavior here at all. If application programmers care about the update count, then they will switch to new xxxLarge methods.
Best
Lance
On Nov 26, 2012, at 5:10 PM, Ulf Zibis wrote:
> Hi Lance,
>
> I would throw an IllegalStateException if invoking e.g. getUpdateCounts on integer overflow.
>
> -Ulf
>
>
> Am 26.11.2012 20:44, schrieb Lance Andersen - Oracle:
>> Hi Joe,
>>
>> Thank you for the sanity check.
>>
>> I had added the following to the top of the javadoc (still playing with the wording):
>>
>> As of Java SE 8, the method getLargeUpdateCount has been added to provide support for update counts that may be exceed Integer.MAX_VALUE and returned by the method Statement.executeLargeBatch. A JDBC driver implementation is required to throw BatchUpdateException(String reason, String SQLState, int vendorCode, long []updateCounts,Throwable cause) if an error occurs during the the execution of Statement.executeLargeBatch. If Statement.executeLargeBatch is invoked it is recommended that getLargeUpdateCounts be called instead of getUpdateCounts in order to avoid a possible overflow of the integer update count.
>>
>>
>> Best
>> Lance
>>
>> On Nov 26, 2012, at 1:51 AM, Joe Darcy wrote:
>>
>>> Hi Lance,
>>>
>>> I don't see an obvious problem with the code, but I strongly suggest documenting the correctness conditions regarding the updateCounts and longUpdateCounts fields; I think that would ease reviewing the new constructors and serialization code.
>>>
>>> Cheers,
>>>
>>> -Joe
>>>
>>> On 11/24/2012 2:05 PM, Lance Andersen - Oracle wrote:
>>>> Hi,
>>>>
>>>> For JDBC 4.2, I am adding methods to allow for larger update counts (request from JDBC driver vendors) and because of this I have to tweak BatchUpdateException
>>>>
>>>> The Statement interface has the method
>>>>
>>>> int[] executeBatch()
>>>>
>>>> I am planning to add
>>>>
>>>> long[] executeLargeBatch().
>>>>
>>>> To accomodate this change, I also need to add a new field and the method getLargeUpdateCount to BatchUpdateException.
>>>>
>>>> I have exchanged emails on this with Alan and he indicated that the changes seemed reasonable but to send a general email out to see if anything was missed from the serialization perspective.
>>>>
>>>> I have added JDBC Unit tests to validate that the serialization/deserialization works between JDBC 4.1 and JDBC 4.2 and they run without a problem.
>>>>
>>>>
>>>> Best
>>>> Lance
>>>>
>>>> new-host-2:sql lanceandersen$ diff BatchUpdateException.java ~/NetBeansProjects/JDBC4.2/jdbc4.0/src/java/sql/
>>>> 2c2
>>>> < * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
>>>> ---
>>>>> * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
>>>> 27a28,31
>>>>> import java.io.IOException;
>>>>> import java.io.InvalidObjectException;
>>>>> import java.io.ObjectInputStream;
>>>>> import java.io.ObjectOutputStream;
>>>> 83a88
>>>>> this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts);
>>>> 192c197
>>>> < this((cause == null ? null : cause.toString()), null, 0, null, cause);
>>>> ---
>>>>> this((cause == null ? null : cause.toString()), null, 0, (int[])null, cause);
>>>> 295a301
>>>>> this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts);
>>>> 331c337,401
>>>> <
>>>> ---
>>>>> /**
>>>>> * Constructs a <code>BatchUpdateException</code> object initialized with
>>>>> * a given <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
>>>>> * <code>cause</code> and <code>updateCounts</code>.
>>>>> * <p>
>>>>> * This constructor should be used when the returned update count may exceed
>>>>> * {@link Integer.MAX_VALUE}.
>>>>> * <p>
>>>>> * @param reason a description of the error
>>>>> * @param SQLState an XOPEN or SQL:2003 code identifying the exception
>>>>> * @param vendorCode an exception code used by a particular
>>>>> * database vendor
>>>>> * @param updateCounts an array of <code>long</code>, with each element
>>>>> *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
>>>>> * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
>>>>> * the batch for JDBC drivers that continue processing
>>>>> * after a command failure; an update count or
>>>>> * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
>>>>> * prior to the failure for JDBC drivers that stop processing after a command
>>>>> * failure
>>>>> * @param cause the underlying reason for this <code>SQLException</code>
>>>>> * (which is saved for later retrieval by the <code>getCause()</code> method);
>>>>> * may be null indicating the cause is non-existent or unknown.
>>>>> * @since 1.8
>>>>> */
>>>>> public BatchUpdateException(String reason, String SQLState, int vendorCode,
>>>>> long []updateCounts,Throwable cause) {
>>>>> super(reason, SQLState, vendorCode, cause);
>>>>> this.longUpdateCounts = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
>>>>> this.updateCounts = (longUpdateCounts == null) ? null : copyUpdateCount(longUpdateCounts);
>>>>> }
>>>>> /**
>>>>> * Retrieves the update count for each update statement in the batch
>>>>> * update that executed successfully before this exception occurred.
>>>>> * A driver that implements batch updates may or may not continue to
>>>>> * process the remaining commands in a batch when one of the commands
>>>>> * fails to execute properly. If the driver continues processing commands,
>>>>> * the array returned by this method will have as many elements as
>>>>> * there are commands in the batch; otherwise, it will contain an
>>>>> * update count for each command that executed successfully before
>>>>> * the <code>BatchUpdateException</code> was thrown.
>>>>> * <p>
>>>>> * This method should be used when the returned update count may exceed
>>>>> * {@link Integer.MAX_VALUE}.
>>>>> * <p>
>>>>> * @return an array of <code>long</code> containing the update counts
>>>>> * for the updates that were executed successfully before this error
>>>>> * occurred. Or, if the driver continues to process commands after an
>>>>> * error, one of the following for every command in the batch:
>>>>> * <OL>
>>>>> * <LI>an update count
>>>>> * <LI><code>Statement.SUCCESS_NO_INFO</code> to indicate that the command
>>>>> * executed successfully but the number of rows affected is unknown
>>>>> * <LI><code>Statement.EXECUTE_FAILED</code> to indicate that the command
>>>>> * failed to execute successfully
>>>>> * </OL>
>>>>> * @since 1.8
>>>>> */
>>>>> public long[] getLargeUpdateCounts() {
>>>>> return (longUpdateCounts == null) ? null :
>>>>> Arrays.copyOf(longUpdateCounts, longUpdateCounts.length);
>>>>> }
>>>>>
>>>> 337c407,414
>>>> < private final int[] updateCounts;
>>>> ---
>>>>> private int[] updateCounts;
>>>>>
>>>>> /**
>>>>> * The array that describes the outcome of a batch execution.
>>>>> * @serial
>>>>> * @since 1.8
>>>>> */
>>>>> private long[] longUpdateCounts;
>>>> 339a417,474
>>>>> /*
>>>>> * Utility method to copy int[] updateCount to long[] updateCount
>>>>> */
>>>>> private static long[] copyUpdateCount(int[] uc) {
>>>>> long[] copy = new long[uc.length];
>>>>> for(int i= 0; i< uc.length; i++) {
>>>>> copy[i] = uc[i];
>>>>> }
>>>>> return copy;
>>>>> }
>>>>> /*
>>>>> * Utility method to copy int[] updateCount to long[] updateCount
>>>>> */
>>>>> private static int[] copyUpdateCount(long[] uc) {
>>>>> int[] copy = new int[uc.length];
>>>>> for(int i= 0; i< uc.length; i++) {
>>>>> copy[i] = (int) uc[i];
>>>>> }
>>>>> return copy;
>>>>> }
>>>>> /**
>>>>> * readObject is called to restore the state of the
>>>>> * {@code BatchUpdateException} from a stream.
>>>>> */
>>>>> private void readObject(ObjectInputStream s)
>>>>> throws IOException, ClassNotFoundException {
>>>>> ObjectInputStream.GetField fields = s.readFields();
>>>>> int[] tmp = (int[])fields.get("updateCounts", null);
>>>>> long[] tmp2 = (long[])fields.get("longUpdateCounts", null);
>>>>> if(tmp != null && tmp2 != null && tmp.length != tmp2.length)
>>>>> throw new InvalidObjectException("update counts are not the expected size");
>>>>> if (tmp != null)
>>>>> updateCounts = tmp.clone();
>>>>> if (tmp2 != null)
>>>>> longUpdateCounts = tmp2.clone();
>>>>> if(updateCounts == null && longUpdateCounts != null)
>>>>> updateCounts = copyUpdateCount(longUpdateCounts);
>>>>> if(longUpdateCounts == null && updateCounts != null)
>>>>> longUpdateCounts = copyUpdateCount(updateCounts);
>>>>>
>>>>> }
>>>>> /**
>>>>> * writeObject is called to save the state of the {@code BatchUpdateException}
>>>>> * to a stream.
>>>>> */
>>>>> private void writeObject(ObjectOutputStream s)
>>>>> throws IOException, ClassNotFoundException {
>>>>>
>>>>> ObjectOutputStream.PutField fields = s.putFields();
>>>>> fields.put("updateCounts", updateCounts);
>>>>> fields.put("longUpdateCounts", longUpdateCounts);
>>>>> s.writeFields();
>>>>> }
>>>>
>>>> Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037
>>>> Oracle Java Engineering
>>>> 1 Network Drive
>>>> Burlington, MA 01803
>>>> Lance.Andersen at oracle.com
>>>>
>>>>
>>
>>
>> Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037
>> Oracle Java Engineering
>> 1 Network Drive
>> Burlington, MA 01803
>> Lance.Andersen at oracle.com
>>
>
Lance Andersen| Principal Member of Technical Staff | +1.781.442.2037
Oracle Java Engineering
1 Network Drive
Burlington, MA 01803
Lance.Andersen at oracle.com
More information about the core-libs-dev
mailing list