1/*
2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.sql;
27
28import java.io.IOException;
29import java.io.InvalidObjectException;
30import java.io.ObjectInputStream;
31import java.io.ObjectOutputStream;
32import java.util.Arrays;
33
34/**
35 * The subclass of {@link SQLException} thrown when an error
36 * occurs during a batch update operation.  In addition to the
37 * information provided by {@link SQLException}, a
38 * <code>BatchUpdateException</code> provides the update
39 * counts for all commands that were executed successfully during the
40 * batch update, that is, all commands that were executed before the error
41 * occurred.  The order of elements in an array of update counts
42 * corresponds to the order in which commands were added to the batch.
43 * <P>
44 * After a command in a batch update fails to execute properly
45 * and a <code>BatchUpdateException</code> is thrown, the driver
46 * may or may not continue to process the remaining commands in
47 * the batch.  If the driver continues processing after a failure,
48 * the array returned by the method
49 * <code>BatchUpdateException.getUpdateCounts</code> will have
50 * an element for every command in the batch rather than only
51 * elements for the commands that executed successfully before
52 * the error.  In the case where the driver continues processing
53 * commands, the array element for any command
54 * that failed is <code>Statement.EXECUTE_FAILED</code>.
55 * <P>
56 * A JDBC driver implementation should use
57 * the constructor {@code BatchUpdateException(String reason, String SQLState,
58 * int vendorCode, long []updateCounts,Throwable cause) } instead of
59 * constructors that take {@code int[]} for the update counts to avoid the
60 * possibility of overflow.
61 * <p>
62 * If {@code Statement.executeLargeBatch} method is invoked it is recommended that
63 * {@code getLargeUpdateCounts} be called instead of {@code getUpdateCounts}
64 * in order to avoid a possible overflow of the integer update count.
65 * @since 1.2
66 */
67
68public class BatchUpdateException extends SQLException {
69
70  /**
71   * Constructs a <code>BatchUpdateException</code> object initialized with a given
72   * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code> and
73   * <code>updateCounts</code>.
74   * The <code>cause</code> is not initialized, and may subsequently be
75   * initialized by a call to the
76   * {@link Throwable#initCause(java.lang.Throwable)} method.
77   * <p>
78   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
79   * overflow and because of this it is recommended that you use the constructor
80   * {@code BatchUpdateException(String reason, String SQLState,
81   * int vendorCode, long []updateCounts,Throwable cause) }.
82   * </p>
83   * @param reason a description of the error
84   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
85   * @param vendorCode an exception code used by a particular
86   * database vendor
87   * @param updateCounts an array of <code>int</code>, with each element
88   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
89   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
90   * the batch for JDBC drivers that continue processing
91   * after a command failure; an update count or
92   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
93   * prior to the failure for JDBC drivers that stop processing after a command
94   * failure
95   * @since 1.2
96   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
97   * java.lang.Throwable)
98   */
99  public BatchUpdateException( String reason, String SQLState, int vendorCode,
100                               int[] updateCounts ) {
101      super(reason, SQLState, vendorCode);
102      this.updateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
103      this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts);
104  }
105
106  /**
107   * Constructs a <code>BatchUpdateException</code> object initialized with a given
108   * <code>reason</code>, <code>SQLState</code> and
109   * <code>updateCounts</code>.
110   * The <code>cause</code> is not initialized, and may subsequently be
111   * initialized by a call to the
112   * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
113   * is initialized to 0.
114   * <p>
115   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
116   * overflow and because of this it is recommended that you use the constructor
117   * {@code BatchUpdateException(String reason, String SQLState,
118   * int vendorCode, long []updateCounts,Throwable cause) }.
119   * </p>
120   * @param reason a description of the exception
121   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
122   * @param updateCounts an array of <code>int</code>, with each element
123   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
124   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
125   * the batch for JDBC drivers that continue processing
126   * after a command failure; an update count or
127   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
128   * prior to the failure for JDBC drivers that stop processing after a command
129   * failure
130   * @since 1.2
131   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
132   * java.lang.Throwable)
133   */
134  public BatchUpdateException(String reason, String SQLState,
135                              int[] updateCounts) {
136      this(reason, SQLState, 0, updateCounts);
137  }
138
139  /**
140   * Constructs a <code>BatchUpdateException</code> object initialized with a given
141   * <code>reason</code> and <code>updateCounts</code>.
142   * The <code>cause</code> is not initialized, and may subsequently be
143   * initialized by a call to the
144   * {@link Throwable#initCause(java.lang.Throwable)} method.  The
145   * <code>SQLState</code> is initialized to <code>null</code>
146   * and the vendor code is initialized to 0.
147   * <p>
148   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
149   * overflow and because of this it is recommended that you use the constructor
150   * {@code BatchUpdateException(String reason, String SQLState,
151   * int vendorCode, long []updateCounts,Throwable cause) }.
152   * </p>
153   * @param reason a description of the exception
154   * @param updateCounts an array of <code>int</code>, with each element
155   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
156   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
157   * the batch for JDBC drivers that continue processing
158   * after a command failure; an update count or
159   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
160   * prior to the failure for JDBC drivers that stop processing after a command
161   * failure
162   * @since 1.2
163   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
164   * java.lang.Throwable)
165   */
166  public  BatchUpdateException(String reason, int[] updateCounts) {
167      this(reason, null, 0, updateCounts);
168  }
169
170  /**
171   * Constructs a <code>BatchUpdateException</code> object initialized with a given
172   * <code>updateCounts</code>.
173   * initialized by a call to the
174   * {@link Throwable#initCause(java.lang.Throwable)} method. The  <code>reason</code>
175   * and <code>SQLState</code> are initialized to null and the vendor code
176   * is initialized to 0.
177   * <p>
178   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
179   * overflow and because of this it is recommended that you use the constructor
180   * {@code BatchUpdateException(String reason, String SQLState,
181   * int vendorCode, long []updateCounts,Throwable cause) }.
182   * </p>
183   * @param updateCounts an array of <code>int</code>, with each element
184   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
185   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
186   * the batch for JDBC drivers that continue processing
187   * after a command failure; an update count or
188   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
189   * prior to the failure for JDBC drivers that stop processing after a command
190   * failure
191   * @since 1.2
192   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
193   * java.lang.Throwable)
194   */
195  public BatchUpdateException(int[] updateCounts) {
196      this(null, null, 0, updateCounts);
197  }
198
199  /**
200   * Constructs a <code>BatchUpdateException</code> object.
201   * The <code>reason</code>, <code>SQLState</code> and <code>updateCounts</code>
202   *  are initialized to <code>null</code> and the vendor code is initialized to 0.
203   * The <code>cause</code> is not initialized, and may subsequently be
204   * initialized by a call to the
205   * {@link Throwable#initCause(java.lang.Throwable)} method.
206   *
207   * @since 1.2
208   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
209   * java.lang.Throwable)
210   */
211  public BatchUpdateException() {
212        this(null, null, 0, null);
213  }
214
215  /**
216   * Constructs a <code>BatchUpdateException</code> object initialized with
217   *  a given <code>cause</code>.
218   * The <code>SQLState</code> and <code>updateCounts</code>
219   * are initialized
220   * to <code>null</code> and the vendor code is initialized to 0.
221   * The <code>reason</code>  is initialized to <code>null</code> if
222   * <code>cause==null</code> or to <code>cause.toString()</code> if
223   *  <code>cause!=null</code>.
224   * @param cause the underlying reason for this <code>SQLException</code>
225   * (which is saved for later retrieval by the <code>getCause()</code> method);
226   * may be null indicating the cause is non-existent or unknown.
227   * @since 1.6
228   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
229   * java.lang.Throwable)
230   */
231  public BatchUpdateException(Throwable cause) {
232      this((cause == null ? null : cause.toString()), null, 0, (int[])null, cause);
233  }
234
235  /**
236   * Constructs a <code>BatchUpdateException</code> object initialized with a
237   * given <code>cause</code> and <code>updateCounts</code>.
238   * The <code>SQLState</code> is initialized
239   * to <code>null</code> and the vendor code is initialized to 0.
240   * The <code>reason</code>  is initialized to <code>null</code> if
241   * <code>cause==null</code> or to <code>cause.toString()</code> if
242   * <code>cause!=null</code>.
243   * <p>
244   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
245   * overflow and because of this it is recommended that you use the constructor
246   * {@code BatchUpdateException(String reason, String SQLState,
247   * int vendorCode, long []updateCounts,Throwable cause) }.
248   * </p>
249   * @param updateCounts an array of <code>int</code>, with each element
250   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
251   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
252   * the batch for JDBC drivers that continue processing
253   * after a command failure; an update count or
254   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
255   * prior to the failure for JDBC drivers that stop processing after a command
256   * failure
257   * @param cause the underlying reason for this <code>SQLException</code>
258   * (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
259   * the cause is non-existent or unknown.
260   * @since 1.6
261   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
262   * java.lang.Throwable)
263   */
264  public BatchUpdateException(int []updateCounts , Throwable cause) {
265      this((cause == null ? null : cause.toString()), null, 0, updateCounts, cause);
266  }
267
268  /**
269   * Constructs a <code>BatchUpdateException</code> object initialized with
270   * a given <code>reason</code>, <code>cause</code>
271   * and <code>updateCounts</code>. The <code>SQLState</code> is initialized
272   * to <code>null</code> and the vendor code is initialized to 0.
273   * <p>
274   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
275   * overflow and because of this it is recommended that you use the constructor
276   * {@code BatchUpdateException(String reason, String SQLState,
277   * int vendorCode, long []updateCounts,Throwable cause) }.
278   * </p>
279   * @param reason a description of the exception
280   * @param updateCounts an array of <code>int</code>, with each element
281   *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
282   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
283   * the batch for JDBC drivers that continue processing
284   * after a command failure; an update count or
285   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
286   * prior to the failure for JDBC drivers that stop processing after a command
287   * failure
288   * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
289   * may be null indicating
290   * the cause is non-existent or unknown.
291   * @since 1.6
292   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
293   * java.lang.Throwable)
294   */
295  public BatchUpdateException(String reason, int []updateCounts, Throwable cause) {
296      this(reason, null, 0, updateCounts, cause);
297  }
298
299  /**
300   * Constructs a <code>BatchUpdateException</code> object initialized with
301   * a given <code>reason</code>, <code>SQLState</code>,<code>cause</code>, and
302   * <code>updateCounts</code>. The vendor code is initialized to 0.
303   *
304   * @param reason a description of the exception
305   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
306   * @param updateCounts an array of <code>int</code>, with each element
307   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
308   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
309   * the batch for JDBC drivers that continue processing
310   * after a command failure; an update count or
311   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
312   * prior to the failure for JDBC drivers that stop processing after a command
313   * failure
314   * <p>
315   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
316   * overflow and because of this it is recommended that you use the constructor
317   * {@code BatchUpdateException(String reason, String SQLState,
318   * int vendorCode, long []updateCounts,Throwable cause) }.
319   * </p>
320   * @param cause the underlying reason for this <code>SQLException</code>
321   * (which is saved for later retrieval by the <code>getCause()</code> method);
322   * may be null indicating
323   * the cause is non-existent or unknown.
324   * @since 1.6
325   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
326   * java.lang.Throwable)
327   */
328  public BatchUpdateException(String reason, String SQLState,
329          int []updateCounts, Throwable cause) {
330      this(reason, SQLState, 0, updateCounts, cause);
331  }
332
333  /**
334   * Constructs a <code>BatchUpdateException</code> object initialized with
335   * a given <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
336   * <code>cause</code> and <code>updateCounts</code>.
337   *
338   * @param reason a description of the error
339   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
340   * @param vendorCode an exception code used by a particular
341   * database vendor
342   * @param updateCounts an array of <code>int</code>, with each element
343   *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
344   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
345   * the batch for JDBC drivers that continue processing
346   * after a command failure; an update count or
347   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
348   * prior to the failure for JDBC drivers that stop processing after a command
349   * failure
350   * <p>
351   * <strong>Note:</strong> There is no validation of {@code updateCounts} for
352   * overflow and because of this it is recommended that you use the constructor
353   * {@code BatchUpdateException(String reason, String SQLState,
354   * int vendorCode, long []updateCounts,Throwable cause) }.
355   * </p>
356   * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
357   * may be null indicating
358   * the cause is non-existent or unknown.
359   * @since 1.6
360   * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
361   * java.lang.Throwable)
362   */
363  public BatchUpdateException(String reason, String SQLState, int vendorCode,
364                                int []updateCounts,Throwable cause) {
365        super(reason, SQLState, vendorCode, cause);
366        this.updateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
367        this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts);
368  }
369
370  /**
371   * Retrieves the update count for each update statement in the batch
372   * update that executed successfully before this exception occurred.
373   * A driver that implements batch updates may or may not continue to
374   * process the remaining commands in a batch when one of the commands
375   * fails to execute properly. If the driver continues processing commands,
376   * the array returned by this method will have as many elements as
377   * there are commands in the batch; otherwise, it will contain an
378   * update count for each command that executed successfully before
379   * the <code>BatchUpdateException</code> was thrown.
380   * <P>
381   * The possible return values for this method were modified for
382   * the Java 2 SDK, Standard Edition, version 1.3.  This was done to
383   * accommodate the new option of continuing to process commands
384   * in a batch update after a <code>BatchUpdateException</code> object
385   * has been thrown.
386   *
387   * @return an array of <code>int</code> containing the update counts
388   * for the updates that were executed successfully before this error
389   * occurred.  Or, if the driver continues to process commands after an
390   * error, one of the following for every command in the batch:
391   * <OL>
392   * <LI>an update count
393   *  <LI><code>Statement.SUCCESS_NO_INFO</code> to indicate that the command
394   *     executed successfully but the number of rows affected is unknown
395   *  <LI><code>Statement.EXECUTE_FAILED</code> to indicate that the command
396   *     failed to execute successfully
397   * </OL>
398   * @since 1.3
399   * @see #getLargeUpdateCounts()
400   */
401  public int[] getUpdateCounts() {
402      return (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
403  }
404
405  /**
406   * Constructs a <code>BatchUpdateException</code> object initialized with
407   * a given <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
408   * <code>cause</code> and <code>updateCounts</code>.
409   * <p>
410   * This constructor should be used when the returned update count may exceed
411   * {@link Integer#MAX_VALUE}.
412   *
413   * @param reason a description of the error
414   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
415   * @param vendorCode an exception code used by a particular
416   * database vendor
417   * @param updateCounts an array of <code>long</code>, with each element
418   *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
419   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
420   * the batch for JDBC drivers that continue processing
421   * after a command failure; an update count or
422   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
423   * prior to the failure for JDBC drivers that stop processing after a command
424   * failure
425   * @param cause the underlying reason for this <code>SQLException</code>
426   * (which is saved for later retrieval by the <code>getCause()</code> method);
427   * may be null indicating the cause is non-existent or unknown.
428   * @since 1.8
429   */
430  public BatchUpdateException(String reason, String SQLState, int vendorCode,
431          long []updateCounts,Throwable cause) {
432      super(reason, SQLState, vendorCode, cause);
433      this.longUpdateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
434      this.updateCounts = (longUpdateCounts == null) ? null : copyUpdateCount(longUpdateCounts);
435  }
436
437  /**
438   * Retrieves the update count for each update statement in the batch
439   * update that executed successfully before this exception occurred.
440   * A driver that implements batch updates may or may not continue to
441   * process the remaining commands in a batch when one of the commands
442   * fails to execute properly. If the driver continues processing commands,
443   * the array returned by this method will have as many elements as
444   * there are commands in the batch; otherwise, it will contain an
445   * update count for each command that executed successfully before
446   * the <code>BatchUpdateException</code> was thrown.
447   * <p>
448   * This method should be used when {@code Statement.executeLargeBatch} is
449   * invoked and the returned update count may exceed {@link Integer#MAX_VALUE}.
450   *
451   * @return an array of <code>long</code> containing the update counts
452   * for the updates that were executed successfully before this error
453   * occurred.  Or, if the driver continues to process commands after an
454   * error, one of the following for every command in the batch:
455   * <OL>
456   * <LI>an update count
457   *  <LI><code>Statement.SUCCESS_NO_INFO</code> to indicate that the command
458   *     executed successfully but the number of rows affected is unknown
459   *  <LI><code>Statement.EXECUTE_FAILED</code> to indicate that the command
460   *     failed to execute successfully
461   * </OL>
462   * @since 1.8
463   */
464  public long[] getLargeUpdateCounts() {
465      return (longUpdateCounts == null) ? null :
466              Arrays.copyOf(longUpdateCounts, longUpdateCounts.length);
467  }
468
469  /**
470   * The array that describes the outcome of a batch execution.
471   * @serial
472   * @since 1.2
473   */
474  private  int[] updateCounts;
475
476  /*
477   * Starting with Java SE 8, JDBC has added support for returning an update
478   * count > Integer.MAX_VALUE.  Because of this the following changes were made
479   * to BatchUpdateException:
480   * <ul>
481   * <li>Add field longUpdateCounts</li>
482   * <li>Add Constructor which takes long[] for update counts</li>
483   * <li>Add getLargeUpdateCounts method</li>
484   * </ul>
485   * When any of the constructors are called, the int[] and long[] updateCount
486   * fields are populated by copying the one array to each other.
487   *
488   * As the JDBC driver passes in the updateCounts, there has always been the
489   * possibility for overflow and BatchUpdateException does not need to account
490   * for that, it simply copies the arrays.
491   *
492   * JDBC drivers should always use the constructor that specifies long[] and
493   * JDBC application developers should call getLargeUpdateCounts.
494   */
495
496  /**
497   * The array that describes the outcome of a batch execution.
498   * @serial
499   * @since 1.8
500   */
501  private  long[] longUpdateCounts;
502
503  private static final long serialVersionUID = 5977529877145521757L;
504
505  /*
506   * Utility method to copy int[] updateCount to long[] updateCount
507   */
508  private static long[] copyUpdateCount(int[] uc) {
509      long[] copy = new long[uc.length];
510      for(int i= 0; i< uc.length; i++) {
511          copy[i] = uc[i];
512      }
513      return copy;
514  }
515
516  /*
517   * Utility method to copy long[] updateCount to int[] updateCount.
518   * No checks for overflow will be done as it is expected a  user will call
519   * getLargeUpdateCounts.
520   */
521  private static int[] copyUpdateCount(long[] uc) {
522      int[] copy = new int[uc.length];
523      for(int i= 0; i< uc.length; i++) {
524          copy[i] = (int) uc[i];
525      }
526      return copy;
527  }
528    /**
529     * readObject is called to restore the state of the
530     * {@code BatchUpdateException} from a stream.
531     */
532    private void readObject(ObjectInputStream s)
533            throws IOException, ClassNotFoundException {
534
535       ObjectInputStream.GetField fields = s.readFields();
536       int[] tmp = (int[])fields.get("updateCounts", null);
537       long[] tmp2 = (long[])fields.get("longUpdateCounts", null);
538       if(tmp != null && tmp2 != null && tmp.length != tmp2.length)
539           throw new InvalidObjectException("update counts are not the expected size");
540       if (tmp != null)
541           updateCounts = tmp.clone();
542       if (tmp2 != null)
543           longUpdateCounts = tmp2.clone();
544       if(updateCounts == null && longUpdateCounts != null)
545           updateCounts = copyUpdateCount(longUpdateCounts);
546       if(longUpdateCounts == null && updateCounts != null)
547           longUpdateCounts = copyUpdateCount(updateCounts);
548
549    }
550
551    /**
552     * writeObject is called to save the state of the {@code BatchUpdateException}
553     * to a stream.
554     */
555    private void writeObject(ObjectOutputStream s)
556            throws IOException, ClassNotFoundException {
557
558        ObjectOutputStream.PutField fields = s.putFields();
559        fields.put("updateCounts", updateCounts);
560        fields.put("longUpdateCounts", longUpdateCounts);
561        s.writeFields();
562    }
563}
564