EMMA Coverage Report (generated Fri May 26 15:35:26 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [Statement.java]

nameclass, %method, %block, %line, %
Statement.java50%  (1/2)85%  (51/60)77%  (2090/2710)78%  (451.9/577)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Statement$CachedResultSetMetaData0%   (0/1)0%   (0/1)0%   (0/12)0%   (0/3)
Statement$CachedResultSetMetaData (Statement): void 0%   (0/1)0%   (0/12)0%   (0/3)
     
class Statement100% (1/1)86%  (51/59)77%  (2090/2698)79%  (451.9/574)
cancel (): void 0%   (0/1)0%   (0/1)0%   (0/1)
execute (String, String []): boolean 0%   (0/1)0%   (0/49)0%   (0/9)
execute (String, int []): boolean 0%   (0/1)0%   (0/49)0%   (0/9)
executeUpdate (String, String []): int 0%   (0/1)0%   (0/49)0%   (0/9)
executeUpdate (String, int []): int 0%   (0/1)0%   (0/49)0%   (0/9)
getCachedMetaData (String): Statement$CachedResultSetMetaData 0%   (0/1)0%   (0/11)0%   (0/3)
getLongUpdateCount (): long 0%   (0/1)0%   (0/14)0%   (0/5)
initializeResultsMetadataFromCache (String, Statement$CachedResultSetMetaData... 0%   (0/1)0%   (0/72)0%   (0/17)
checkNullOrEmptyQuery (String): void 100% (1/1)30%  (6/20)60%  (3/5)
closeAllOpenResults (): void 100% (1/1)54%  (14/26)44%  (4/9)
getMoreResults (int): boolean 100% (1/1)65%  (64/99)59%  (16/27)
execute (String, int): boolean 100% (1/1)66%  (31/47)76%  (6.8/9)
executeUpdate (String, int): int 100% (1/1)66%  (31/47)76%  (6.8/9)
setQueryTimeout (int): void 100% (1/1)69%  (9/13)50%  (2/4)
execute (String): boolean 100% (1/1)72%  (202/281)80%  (39.9/50)
getBatchedGeneratedKeys (): void 100% (1/1)81%  (30/37)85%  (6.8/8)
getBatchedGeneratedKeys (Statement): void 100% (1/1)81%  (30/37)85%  (6.8/8)
executeUpdate (String, boolean): int 100% (1/1)83%  (149/180)87%  (33/38)
getWarnings (): SQLWarning 100% (1/1)83%  (25/30)88%  (7/8)
executeQuery (String): ResultSet 100% (1/1)85%  (212/250)82%  (32.9/40)
getRecordCountFromInfo (String): int 100% (1/1)88%  (89/101)90%  (28.7/32)
getUpdateCount (): int 100% (1/1)90%  (26/29)89%  (8/9)
executeBatch (): int [] 100% (1/1)93%  (188/203)97%  (35/36)
executeBatchUsingMultiQueries (boolean, int): int [] 100% (1/1)96%  (245/256)94%  (47.2/50)
Statement (Connection, String): void 100% (1/1)96%  (182/189)98%  (48/49)
setMaxFieldSize (int): void 100% (1/1)98%  (41/42)99%  (6.9/7)
realClose (boolean): void 100% (1/1)99%  (105/106)96%  (25/26)
<static initializer> 100% (1/1)100% (3/3)100% (1/1)
addBatch (String): void 100% (1/1)100% (16/16)100% (5/5)
checkClosed (): void 100% (1/1)100% (11/11)100% (3/3)
checkForDml (String, char): void 100% (1/1)100% (47/47)100% (4/4)
clearBatch (): void 100% (1/1)100% (7/7)100% (3/3)
clearWarnings (): void 100% (1/1)100% (4/4)100% (2/2)
close (): void 100% (1/1)100% (4/4)100% (2/2)
createStreamingResultSet (): boolean 100% (1/1)100% (16/16)100% (1/1)
enableStreamingResults (): void 100% (1/1)100% (7/7)100% (3/3)
executeUpdate (String): int 100% (1/1)100% (5/5)100% (1/1)
getConnection (): Connection 100% (1/1)100% (3/3)100% (1/1)
getFetchDirection (): int 100% (1/1)100% (2/2)100% (1/1)
getFetchSize (): int 100% (1/1)100% (3/3)100% (1/1)
getGeneratedKeys (): ResultSet 100% (1/1)100% (40/40)100% (6/6)
getGeneratedKeysInternal (): ResultSet 100% (1/1)100% (96/96)100% (16/16)
getId (): int 100% (1/1)100% (3/3)100% (1/1)
getLastInsertID (): long 100% (1/1)100% (3/3)100% (1/1)
getMaxFieldSize (): int 100% (1/1)100% (3/3)100% (1/1)
getMaxRows (): int 100% (1/1)100% (8/8)100% (3/3)
getMoreResults (): boolean 100% (1/1)100% (4/4)100% (1/1)
getQueryTimeout (): int 100% (1/1)100% (3/3)100% (1/1)
getResultSet (): ResultSet 100% (1/1)100% (12/12)100% (1/1)
getResultSetConcurrency (): int 100% (1/1)100% (3/3)100% (1/1)
getResultSetHoldability (): int 100% (1/1)100% (2/2)100% (1/1)
getResultSetType (): int 100% (1/1)100% (3/3)100% (1/1)
setCursorName (String): void 100% (1/1)100% (1/1)100% (1/1)
setEscapeProcessing (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setFetchDirection (int): void 100% (1/1)100% (11/11)100% (4/4)
setFetchSize (int): void 100% (1/1)100% (27/27)100% (4/4)
setMaxRows (int): void 100% (1/1)100% (52/52)100% (11/11)
setResultSetConcurrency (int): void 100% (1/1)100% (4/4)100% (2/2)
setResultSetType (int): void 100% (1/1)100% (4/4)100% (2/2)

1/*
2 Copyright (C) 2002-2004 MySQL AB
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of version 2 of the GNU General Public License as 
6 published by the Free Software Foundation.
7 
8 There are special exceptions to the terms and conditions of the GPL 
9 as it is applied to this software. View the full text of the 
10 exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
11 software distribution.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 
23 
24 */
25package com.mysql.jdbc;
26 
27import com.mysql.jdbc.profiler.ProfileEventSink;
28import com.mysql.jdbc.profiler.ProfilerEvent;
29import com.mysql.jdbc.util.LRUCache;
30 
31import java.sql.DataTruncation;
32import java.sql.SQLException;
33import java.sql.SQLWarning;
34import java.sql.Types;
35 
36import java.util.ArrayList;
37import java.util.Iterator;
38import java.util.List;
39import java.util.Locale;
40import java.util.Map;
41 
42/**
43 * A Statement object is used for executing a static SQL statement and obtaining
44 * the results produced by it.
45 * 
46 * <p>
47 * Only one ResultSet per Statement can be open at any point in time. Therefore,
48 * if the reading of one ResultSet is interleaved with the reading of another,
49 * each must have been generated by different Statements. All statement execute
50 * methods implicitly close a statement's current ResultSet if an open one
51 * exists.
52 * </p>
53 * 
54 * @author Mark Matthews
55 * @version $Id: Statement.java 5123 2006-04-03 12:44:51 -0500 (Mon, 03 Apr 2006) mmatthews $
56 * 
57 * @see java.sql.Statement
58 * @see ResultSet
59 */
60public class Statement implements java.sql.Statement {
61        class CachedResultSetMetaData {
62                /** Map column names (and all of their permutations) to column indices */
63                Map columnNameToIndex = null;
64 
65                /** Cached Field info */
66                Field[] fields;
67 
68                /** Map of fully-specified column names to column indices */
69                Map fullColumnNameToIndex = null;
70 
71                /** Cached ResultSetMetaData */
72                java.sql.ResultSetMetaData metadata;
73        }
74 
75        /** Used to generate IDs when profiling. */
76        protected static int statementCounter = 1;
77 
78        public final static byte USES_VARIABLES_FALSE = 0;
79 
80        public final static byte USES_VARIABLES_TRUE = 1;
81 
82        public final static byte USES_VARIABLES_UNKNOWN = -1;
83 
84        /** Holds batched commands */
85        protected List batchedArgs;
86 
87        /** The character converter to use (if available) */
88        protected SingleByteCharsetConverter charConverter = null;
89 
90        /** The character encoding to use (if available) */
91        protected String charEncoding = null;
92 
93        /** The connection that created us */
94        protected Connection connection = null;
95 
96        /** The catalog in use */
97        protected String currentCatalog = null;
98 
99        /** Should we process escape codes? */
100        protected boolean doEscapeProcessing = true;
101 
102        /** If we're profiling, where should events go to? */
103        protected ProfileEventSink eventSink = null;
104 
105        /** The number of rows to fetch at a time (currently ignored) */
106        private int fetchSize = 0;
107 
108        /** Has this statement been closed? */
109        protected boolean isClosed = false;
110 
111        /** The auto_increment value for the last insert */
112        protected long lastInsertId = -1;
113 
114        /** The max field size for this statement */
115        protected int maxFieldSize = MysqlIO.getMaxBuf();
116 
117        /**
118         * The maximum number of rows to return for this statement (-1 means _all_
119         * rows)
120         */
121        protected int maxRows = -1;
122 
123        /** Has someone changed this for this statement? */
124        protected boolean maxRowsChanged = false;
125 
126        /** List of currently-open ResultSets */
127        protected List openResults = new ArrayList();
128 
129        /** Are we in pedantic mode? */
130        protected boolean pedantic = false;
131 
132        /**
133         * Where this statement was created, only used if profileSql or
134         * useUsageAdvisor set to true.
135         */
136        protected Throwable pointOfOrigin;
137 
138        /** Should we profile? */
139        protected boolean profileSQL = false;
140 
141        /** The current results */
142        protected ResultSet results = null;
143 
144        /** The concurrency for this result set (updatable or not) */
145        protected int resultSetConcurrency = 0;
146 
147        /** Cache of ResultSet metadata */
148        protected LRUCache resultSetMetadataCache;
149 
150        /** The type of this result set (scroll sensitive or in-sensitive) */
151        protected int resultSetType = 0;
152 
153        /** Used to identify this statement when profiling. */
154        protected int statementId;
155 
156        /** The timeout for a query */
157        protected int timeout = 0;
158 
159        /** The update count for this statement */
160        protected long updateCount = -1;
161 
162        /** Should we use the usage advisor? */
163        protected boolean useUsageAdvisor = false;
164 
165        /** The warnings chain. */
166        protected SQLWarning warningChain = null;
167 
168        protected ArrayList batchedGeneratedKeys = null;
169 
170        protected boolean retrieveGeneratedKeys = false;
171 
172        /**
173         * Constructor for a Statement.
174         * 
175         * @param c
176         *            the Connection instantation that creates us
177         * @param catalog
178         *            the database name in use when we were created
179         * 
180         * @throws SQLException
181         *             if an error occurs.
182         */
183        public Statement(Connection c, String catalog) throws SQLException {
184                if ((c == null) || c.isClosed()) {
185                        throw new SQLException(Messages.getString("Statement.0"), //$NON-NLS-1$
186                                        SQLError.SQL_STATE_CONNECTION_NOT_OPEN); //$NON-NLS-1$ //$NON-NLS-2$
187                }
188 
189                this.connection = c;
190                this.currentCatalog = catalog;
191                this.pedantic = this.connection.getPedantic();
192 
193                if (!this.connection.getDontTrackOpenResources()) {
194                        this.connection.registerStatement(this);
195                }
196 
197                //
198                // Adjust, if we know it
199                //
200                if (this.connection != null) {
201                        this.maxFieldSize = this.connection.getMaxAllowedPacket();
202                }
203 
204                if (this.connection.getUseUnicode()) {
205                        this.charEncoding = this.connection.getEncoding();
206 
207                        this.charConverter = this.connection
208                                        .getCharsetConverter(this.charEncoding);
209                }
210 
211                boolean profiling = this.connection.getProfileSql()
212                                || this.connection.getUseUsageAdvisor();
213 
214                if (this.connection.getAutoGenerateTestcaseScript() || profiling) {
215                        this.statementId = statementCounter++;
216                }
217 
218                if (profiling) {
219                        this.pointOfOrigin = new Throwable();
220                        this.profileSQL = this.connection.getProfileSql();
221                        this.useUsageAdvisor = this.connection.getUseUsageAdvisor();
222                        this.eventSink = ProfileEventSink.getInstance(this.connection);
223                }
224 
225                int maxRowsConn = this.connection.getMaxRows();
226 
227                if (maxRowsConn != -1) {
228                        setMaxRows(maxRowsConn);
229                }
230        }
231 
232        /**
233         * DOCUMENT ME!
234         * 
235         * @param sql
236         *            DOCUMENT ME!
237         * 
238         * @throws SQLException
239         *             DOCUMENT ME!
240         */
241        public synchronized void addBatch(String sql) throws SQLException {
242                if (this.batchedArgs == null) {
243                        this.batchedArgs = new ArrayList();
244                }
245 
246                if (sql != null) {
247                        this.batchedArgs.add(sql);
248                }
249        }
250 
251        /**
252         * Cancel can be used by one thread to cancel a statement that is being
253         * executed by another thread. However this driver is synchronous, so this
254         * really has no meaning - we define it as a no-op (i.e. you can't cancel,
255         * but there is no error if you try.)
256         * 
257         * @exception SQLException
258         *                only because thats the spec.
259         */
260        public void cancel() throws SQLException {
261                // No-op
262        }
263 
264        // --------------------------JDBC 2.0-----------------------------
265 
266        /**
267         * Checks if closed() has been called, and throws an exception if so
268         * 
269         * @throws SQLException
270         *             if this statement has been closed
271         */
272        protected void checkClosed() throws SQLException {
273                if (this.isClosed) {
274                        throw new SQLException(Messages.getString("Statement.49"), //$NON-NLS-1$
275                                        SQLError.SQL_STATE_CONNECTION_NOT_OPEN); //$NON-NLS-1$
276                }
277        }
278 
279        /**
280         * Checks if the given SQL query with the given first non-ws char is a DML
281         * statement. Throws an exception if it is.
282         * 
283         * @param sql
284         *            the SQL to check
285         * @param firstStatementChar
286         *            the UC first non-ws char of the statement
287         * 
288         * @throws SQLException
289         *             if the statement contains DML
290         */
291        protected void checkForDml(String sql, char firstStatementChar)
292                        throws SQLException {
293                if ((firstStatementChar == 'I') || (firstStatementChar == 'U')
294                                || (firstStatementChar == 'D') || (firstStatementChar == 'A')
295                                || (firstStatementChar == 'C')) {
296                        if (StringUtils.startsWithIgnoreCaseAndWs(sql, "INSERT") //$NON-NLS-1$
297                                        || StringUtils.startsWithIgnoreCaseAndWs(sql, "UPDATE") //$NON-NLS-1$
298                                        || StringUtils.startsWithIgnoreCaseAndWs(sql, "DELETE") //$NON-NLS-1$
299                                        || StringUtils.startsWithIgnoreCaseAndWs(sql, "DROP") //$NON-NLS-1$
300                                        || StringUtils.startsWithIgnoreCaseAndWs(sql, "CREATE") //$NON-NLS-1$
301                                        || StringUtils.startsWithIgnoreCaseAndWs(sql, "ALTER")) { //$NON-NLS-1$
302                                throw new SQLException(Messages.getString("Statement.57"), //$NON-NLS-1$
303                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
304                        }
305                }
306        }
307 
308        /**
309         * Method checkNullOrEmptyQuery.
310         * 
311         * @param sql
312         *            the SQL to check
313         * 
314         * @throws SQLException
315         *             if query is null or empty.
316         */
317        protected void checkNullOrEmptyQuery(String sql) throws SQLException {
318                if (sql == null) {
319                        throw new SQLException(Messages.getString("Statement.59"), //$NON-NLS-1$
320                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
321                }
322 
323                if (sql.length() == 0) {
324                        throw new SQLException(Messages.getString("Statement.61"), //$NON-NLS-1$
325                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
326                }
327        }
328 
329        /**
330         * JDBC 2.0 Make the set of commands in the current batch empty. This method
331         * is optional.
332         * 
333         * @exception SQLException
334         *                if a database-access error occurs, or the driver does not
335         *                support batch statements
336         */
337        public synchronized void clearBatch() throws SQLException {
338                if (this.batchedArgs != null) {
339                        this.batchedArgs.clear();
340                }
341        }
342 
343        /**
344         * After this call, getWarnings returns null until a new warning is reported
345         * for this Statement.
346         * 
347         * @exception SQLException
348         *                if a database access error occurs (why?)
349         */
350        public synchronized void clearWarnings() throws SQLException {
351                this.warningChain = null;
352        }
353 
354        /**
355         * In many cases, it is desirable to immediately release a Statement's
356         * database and JDBC resources instead of waiting for this to happen when it
357         * is automatically closed. The close method provides this immediate
358         * release.
359         * 
360         * <p>
361         * <B>Note:</B> A Statement is automatically closed when it is garbage
362         * collected. When a Statement is closed, its current ResultSet, if one
363         * exists, is also closed.
364         * </p>
365         * 
366         * @exception SQLException
367         *                if a database access error occurs
368         */
369        public synchronized void close() throws SQLException {
370                realClose(true);
371        }
372 
373        /**
374         * Close any open result sets that have been 'held open'
375         */
376        protected void closeAllOpenResults() {
377                if (this.openResults != null) {
378                        for (Iterator iter = this.openResults.iterator(); iter.hasNext();) {
379                                ResultSet element = (ResultSet) iter.next();
380 
381                                try {
382                                        element.realClose(false);
383                                } catch (SQLException sqlEx) {
384                                        AssertionFailedException.shouldNotHappen(sqlEx);
385                                }
386                        }
387 
388                        this.openResults.clear();
389                }
390        }
391 
392        /**
393         * We only stream result sets when they are forward-only, read-only, and the
394         * fetch size has been set to Integer.MIN_VALUE
395         * 
396         * @return true if this result set should be streamed row at-a-time, rather
397         *         than read all at once.
398         */
399        protected boolean createStreamingResultSet() {
400                return ((this.resultSetType == java.sql.ResultSet.TYPE_FORWARD_ONLY)
401                                && (this.resultSetConcurrency == java.sql.ResultSet.CONCUR_READ_ONLY) && (this.fetchSize == Integer.MIN_VALUE));
402        }
403 
404        /**
405         * Workaround for containers that 'check' for sane values of
406         * Statement.setFetchSize().
407         * 
408         * @throws SQLException
409         */
410        public void enableStreamingResults() throws SQLException {
411                setFetchSize(Integer.MIN_VALUE);
412                setResultSetType(ResultSet.TYPE_FORWARD_ONLY);
413        }
414 
415        /**
416         * Execute a SQL statement that may return multiple results. We don't have
417         * to worry about this since we do not support multiple ResultSets. You can
418         * use getResultSet or getUpdateCount to retrieve the result.
419         * 
420         * @param sql
421         *            any SQL statement
422         * 
423         * @return true if the next result is a ResulSet, false if it is an update
424         *         count or there are no more results
425         * 
426         * @exception SQLException
427         *                if a database access error occurs
428         */
429        public synchronized boolean execute(String sql) throws SQLException {
430                checkNullOrEmptyQuery(sql);
431 
432                checkClosed();
433 
434                char firstNonWsChar = StringUtils.firstNonWsCharUc(sql);
435 
436                boolean isSelect = true;
437 
438                if (firstNonWsChar != 'S') {
439                        isSelect = false;
440 
441                        if (this.connection.isReadOnly()) {
442                                throw new SQLException(Messages.getString("Statement.27") //$NON-NLS-1$
443                                                + Messages.getString("Statement.28"), //$NON-NLS-1$
444                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
445                        }
446                }
447 
448                if (this.doEscapeProcessing) {
449                        Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
450                                        this.connection.serverSupportsConvertFn());
451 
452                        if (escapedSqlResult instanceof String) {
453                                sql = (String) escapedSqlResult;
454                        } else {
455                                sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
456                        }
457                }
458 
459                if (this.results != null) {
460                        if (!this.connection.getHoldResultsOpenOverStatementClose()) {
461                                this.results.realClose(false);
462                        }
463                }
464 
465                CachedResultSetMetaData cachedMetaData = null;
466 
467                ResultSet rs = null;
468 
469                // If there isn't a limit clause in the SQL
470                // then limit the number of rows to return in
471                // an efficient manner. Only do this if
472                // setMaxRows() hasn't been used on any Statements
473                // generated from the current Connection (saves
474                // a query, and network traffic).
475                synchronized (this.connection.getMutex()) {
476                        this.batchedGeneratedKeys = null;
477                        
478                        String oldCatalog = null;
479 
480                        if (!this.connection.getCatalog().equals(this.currentCatalog)) {
481                                oldCatalog = this.connection.getCatalog();
482                                this.connection.setCatalog(this.currentCatalog);
483                        }
484 
485                        //
486                        // Check if we have cached metadata for this query...
487                        //
488                        if (this.connection.getCacheResultSetMetadata()) {
489                                cachedMetaData = getCachedMetaData(sql);
490                        }
491 
492                        //
493                        // Only apply max_rows to selects
494                        //
495                        if (this.connection.useMaxRows()) {
496                                int rowLimit = -1;
497 
498                                if (isSelect) {
499                                        if (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1) { //$NON-NLS-1$
500                                                rowLimit = this.maxRows;
501                                        } else {
502                                                if (this.maxRows <= 0) {
503                                                        this.connection.execSQL(this,
504                                                                        "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, //$NON-NLS-1$
505                                                                        null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
506                                                                        java.sql.ResultSet.CONCUR_READ_ONLY, false,
507                                                                        false, this.currentCatalog, true); //$NON-NLS-1$
508                                                } else {
509                                                        this.connection
510                                                                        .execSQL(
511                                                                                        this,
512                                                                                        "SET OPTION SQL_SELECT_LIMIT=" + this.maxRows, //$NON-NLS-1$
513                                                                                        -1,
514                                                                                        null,
515                                                                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
516                                                                                        java.sql.ResultSet.CONCUR_READ_ONLY,
517                                                                                        false, false, this.currentCatalog,
518                                                                                        true); //$NON-NLS-1$
519                                                }
520                                        }
521                                } else {
522                                        this.connection.execSQL(this,
523                                                        "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
524                                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
525                                                        java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
526                                                        this.currentCatalog, true); //$NON-NLS-1$
527                                }
528 
529                                // Finally, execute the query
530                                rs = this.connection.execSQL(this, sql, rowLimit, null,
531                                                this.resultSetType, this.resultSetConcurrency,
532                                                createStreamingResultSet(), isSelect,
533                                                this.currentCatalog, (cachedMetaData == null));
534                        } else {
535                                rs = this.connection.execSQL(this, sql, -1, null,
536                                                this.resultSetType, this.resultSetConcurrency,
537                                                createStreamingResultSet(), isSelect,
538                                                this.currentCatalog, (cachedMetaData == null));
539                        }
540 
541                        if (oldCatalog != null) {
542                                this.connection.setCatalog(oldCatalog);
543                        }
544                }
545 
546                this.lastInsertId = rs.getUpdateID();
547 
548                if (rs != null) {
549                        this.results = rs;
550 
551                        rs.setFirstCharOfQuery(firstNonWsChar);
552 
553                        if (rs.reallyResult()) {
554                                if (cachedMetaData != null) {
555                                        initializeResultsMetadataFromCache(sql, cachedMetaData,
556                                                        this.results);
557                                } else {
558                                        if (this.connection.getCacheResultSetMetadata()) {
559                                                initializeResultsMetadataFromCache(sql,
560                                                                null /* will be created */, this.results);
561                                        }
562                                }
563                        }
564                }
565 
566                return ((rs != null) && rs.reallyResult());
567        }
568 
569        /**
570         * @see Statement#execute(String, int)
571         */
572        public boolean execute(String sql, int returnGeneratedKeys)
573                        throws SQLException {
574                if (returnGeneratedKeys == java.sql.Statement.RETURN_GENERATED_KEYS) {
575                        checkClosed();
576 
577                        synchronized (this.connection.getMutex()) {
578                                // If this is a 'REPLACE' query, we need to be able to parse
579                                // the 'info' message returned from the server to determine
580                                // the actual number of keys generated.
581                                boolean readInfoMsgState = this.connection
582                                                .isReadInfoMsgEnabled();
583                                this.connection.setReadInfoMsgEnabled(true);
584 
585                                try {
586                                        return execute(sql);
587                                } finally {
588                                        this.connection.setReadInfoMsgEnabled(readInfoMsgState);
589                                }
590                        }
591                }
592 
593                return execute(sql);
594        }
595 
596        /**
597         * @see Statement#execute(String, int[])
598         */
599        public boolean execute(String sql, int[] generatedKeyIndices)
600                        throws SQLException {
601                if ((generatedKeyIndices != null) && (generatedKeyIndices.length > 0)) {
602                        checkClosed();
603 
604                        synchronized (this.connection.getMutex()) {
605                                // If this is a 'REPLACE' query, we need to be able to parse
606                                // the 'info' message returned from the server to determine
607                                // the actual number of keys generated.
608                                boolean readInfoMsgState = this.connection
609                                                .isReadInfoMsgEnabled();
610                                this.connection.setReadInfoMsgEnabled(true);
611 
612                                try {
613                                        return execute(sql);
614                                } finally {
615                                        this.connection.setReadInfoMsgEnabled(readInfoMsgState);
616                                }
617                        }
618                }
619 
620                return execute(sql);
621        }
622 
623        /**
624         * @see Statement#execute(String, String[])
625         */
626        public boolean execute(String sql, String[] generatedKeyNames)
627                        throws SQLException {
628                if ((generatedKeyNames != null) && (generatedKeyNames.length > 0)) {
629                        checkClosed();
630 
631                        synchronized (this.connection.getMutex()) {
632                                // If this is a 'REPLACE' query, we need to be able to parse
633                                // the 'info' message returned from the server to determine
634                                // the actual number of keys generated.
635                                boolean readInfoMsgState = this.connection
636                                                .isReadInfoMsgEnabled();
637                                this.connection.setReadInfoMsgEnabled(true);
638 
639                                try {
640                                        return execute(sql);
641                                } finally {
642                                        this.connection.setReadInfoMsgEnabled(readInfoMsgState);
643                                }
644                        }
645                }
646 
647                return execute(sql);
648        }
649 
650        /**
651         * JDBC 2.0 Submit a batch of commands to the database for execution. This
652         * method is optional.
653         * 
654         * @return an array of update counts containing one element for each command
655         *         in the batch. The array is ordered according to the order in
656         *         which commands were inserted into the batch
657         * 
658         * @exception SQLException
659         *                if a database-access error occurs, or the driver does not
660         *                support batch statements
661         * @throws java.sql.BatchUpdateException
662         *             DOCUMENT ME!
663         */
664        public synchronized int[] executeBatch() throws SQLException {
665                if (this.connection.isReadOnly()) {
666                        throw new SQLException(Messages.getString("Statement.34") //$NON-NLS-1$
667                                        + Messages.getString("Statement.35"), //$NON-NLS-1$
668                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
669                }
670 
671                if (this.results != null) {
672                        if (!this.connection.getHoldResultsOpenOverStatementClose()) {
673                                this.results.realClose(false);
674                        }
675                }
676 
677                synchronized (this.connection.getMutex()) {
678                        try {
679                                this.retrieveGeneratedKeys = true;
680                                
681                                int[] updateCounts = null;
682        
683                                if (this.batchedArgs != null) {
684                                        
685                                        int nbrCommands = this.batchedArgs.size();
686 
687                                        this.batchedGeneratedKeys = new ArrayList(this.batchedArgs.size());
688                                        
689                                        boolean multiQueriesEnabled = this.connection.getAllowMultiQueries();
690                                        
691                                        if (this.connection.versionMeetsMinimum(4, 1, 1) && 
692                                                        (multiQueriesEnabled || 
693                                                        (this.connection.getRewriteBatchedStatements() && 
694                                                                        nbrCommands > 4))) {
695                                                return executeBatchUsingMultiQueries(multiQueriesEnabled, nbrCommands);
696                                        }
697                                        
698                                        updateCounts = new int[nbrCommands];
699        
700                                        for (int i = 0; i < nbrCommands; i++) {
701                                                updateCounts[i] = -3;
702                                        }
703        
704                                        SQLException sqlEx = null;
705        
706                                        int commandIndex = 0;
707        
708                                        for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
709                                                try {
710                                                        updateCounts[commandIndex] = executeUpdate((String) this.batchedArgs
711                                                                        .get(commandIndex), true);
712                                                        getBatchedGeneratedKeys();
713                                                } catch (SQLException ex) {
714                                                        updateCounts[commandIndex] = EXECUTE_FAILED;
715        
716                                                        if (this.connection.getContinueBatchOnError()) {
717                                                                sqlEx = ex;
718                                                        } else {
719                                                                int[] newUpdateCounts = new int[commandIndex];
720                                                                System.arraycopy(updateCounts, 0, newUpdateCounts,
721                                                                                0, commandIndex);
722        
723                                                                throw new java.sql.BatchUpdateException(ex
724                                                                                .getMessage(), ex.getSQLState(), ex
725                                                                                .getErrorCode(), newUpdateCounts);
726                                                        }
727                                                }
728                                        }
729        
730                                        if (sqlEx != null) {
731                                                throw new java.sql.BatchUpdateException(sqlEx.getMessage(),
732                                                                sqlEx.getSQLState(), sqlEx.getErrorCode(),
733                                                                updateCounts);
734                                        }
735                                }
736        
737                                return (updateCounts != null) ? updateCounts : new int[0];
738                        } finally {
739                                this.retrieveGeneratedKeys = false;
740                                
741                                clearBatch();
742                        }
743                }
744        }
745 
746        /**
747         * Rewrites batch into a single query to send to the server. This method
748         * will constrain each batch to be shorter than max_allowed_packet on the
749         * server.
750         * 
751         * @return update counts in the same manner as executeBatch()
752         * @throws SQLException
753         */
754        private int[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled,
755                        int nbrCommands) throws SQLException {
756 
757                if (!multiQueriesEnabled) {
758                        this.connection.getIO().enableMultiQueries();
759                }
760 
761                try {
762                        int[] updateCounts = new int[nbrCommands];
763 
764                        for (int i = 0; i < nbrCommands; i++) {
765                                updateCounts[i] = -3;
766                        }
767 
768                        int commandIndex = 0;
769 
770                        StringBuffer queryBuf = new StringBuffer();
771 
772                        java.sql.Statement batchStmt = this.connection.createStatement();
773 
774                        int counter = 0;
775 
776                        int numberOfBytesPerChar = 1;
777 
778                        String connectionEncoding = this.connection.getEncoding();
779 
780                        if (StringUtils.startsWithIgnoreCase(connectionEncoding, "utf")) {
781                                numberOfBytesPerChar = 3;
782                        } else if (CharsetMapping.isMultibyteCharset(connectionEncoding)) {
783                                numberOfBytesPerChar = 2;
784                        }
785 
786                        int escapeAdjust = 1;
787                        
788                        if (this.doEscapeProcessing) {
789                                escapeAdjust = 2; /* We assume packet _could_ grow by this amount, as we're not
790                                                     sure how big statement will end up after
791                                                     escape processing */
792                        }
793                        
794                        for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
795                                String nextQuery = (String) this.batchedArgs.get(commandIndex);
796 
797                                if (((((queryBuf.length() + nextQuery.length())
798                                                * numberOfBytesPerChar) + 1 /* for semicolon */ 
799                                                + MysqlIO.HEADER_LENGTH) * escapeAdjust)  + 32 > this.connection
800                                                .getMaxAllowedPacket()) {
801                                        batchStmt.execute(queryBuf.toString());
802 
803                                        updateCounts[counter++] = batchStmt.getUpdateCount();
804                                        long generatedKeyStart = ((com.mysql.jdbc.Statement)batchStmt).getLastInsertID();
805                                        byte[][] row = new byte[1][];
806                                        row[0] = Long.toString(generatedKeyStart++).getBytes();
807                                        this.batchedGeneratedKeys.add(row);
808 
809                                        while (batchStmt.getMoreResults()
810                                                        || batchStmt.getUpdateCount() != -1) {
811                                                updateCounts[counter++] = batchStmt.getUpdateCount();
812                                                row = new byte[1][];
813                                                row[0] = Long.toString(generatedKeyStart++).getBytes();
814                                                this.batchedGeneratedKeys.add(row);
815                                        }
816 
817                                        queryBuf = new StringBuffer();
818                                }
819 
820                                queryBuf.append(nextQuery);
821                                queryBuf.append(";");
822                        }
823 
824                        if (queryBuf.length() > 0) {
825                                batchStmt.execute(queryBuf.toString());
826                                
827                                long generatedKeyStart = ((com.mysql.jdbc.Statement)batchStmt).getLastInsertID();
828                                byte[][] row = new byte[1][];
829                                row[0] = Long.toString(generatedKeyStart++).getBytes();
830                                this.batchedGeneratedKeys.add(row);
831                                
832                                updateCounts[counter++] = batchStmt.getUpdateCount();
833                                
834                                
835                                while (batchStmt.getMoreResults()
836                                                || batchStmt.getUpdateCount() != -1) {
837                                        updateCounts[counter++] = batchStmt.getUpdateCount();
838                                        row = new byte[1][];
839                                        row[0] = Long.toString(generatedKeyStart++).getBytes();
840                                        this.batchedGeneratedKeys.add(row);
841                                }
842                        }
843 
844                        return (updateCounts != null) ? updateCounts : new int[0];
845                } finally {
846                        if (!multiQueriesEnabled) {
847                                this.connection.getIO().disableMultiQueries();
848                        }
849                }
850        }
851 
852        /**
853         * Execute a SQL statement that retruns a single ResultSet
854         * 
855         * @param sql
856         *            typically a static SQL SELECT statement
857         * 
858         * @return a ResulSet that contains the data produced by the query
859         * 
860         * @exception SQLException
861         *                if a database access error occurs
862         */
863        public synchronized java.sql.ResultSet executeQuery(String sql)
864                        throws SQLException {
865                checkNullOrEmptyQuery(sql);
866 
867                checkClosed();
868 
869                if (this.doEscapeProcessing) {
870                        Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
871                                        this.connection.serverSupportsConvertFn());
872 
873                        if (escapedSqlResult instanceof String) {
874                                sql = (String) escapedSqlResult;
875                        } else {
876                                sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
877                        }
878                }
879 
880                char firstStatementChar = StringUtils.firstNonWsCharUc(sql);
881 
882                checkForDml(sql, firstStatementChar);
883 
884                if (this.results != null) {
885                        if (!this.connection.getHoldResultsOpenOverStatementClose()) {
886                                this.results.realClose(false);
887                        }
888                }
889 
890                CachedResultSetMetaData cachedMetaData = null;
891 
892                // If there isn't a limit clause in the SQL
893                // then limit the number of rows to return in
894                // an efficient manner. Only do this if
895                // setMaxRows() hasn't been used on any Statements
896                // generated from the current Connection (saves
897                // a query, and network traffic).
898                synchronized (this.connection.getMutex()) {
899                        this.batchedGeneratedKeys = null;
900                        
901                        String oldCatalog = null;
902 
903                        if (!this.connection.getCatalog().equals(this.currentCatalog)) {
904                                oldCatalog = this.connection.getCatalog();
905                                this.connection.setCatalog(this.currentCatalog);
906                        }
907 
908                        //
909                        // Check if we have cached metadata for this query...
910                        //
911                        if (this.connection.getCacheResultSetMetadata()) {
912                                cachedMetaData = getCachedMetaData(sql);
913                        }
914 
915                        if (this.connection.useMaxRows()) {
916                                // We need to execute this all together
917                                // So synchronize on the Connection's mutex (because
918                                // even queries going through there synchronize
919                                // on the connection
920                                if (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1) { //$NON-NLS-1$
921                                        this.results = this.connection.execSQL(this, sql,
922                                                        this.maxRows, null, this.resultSetType,
923                                                        this.resultSetConcurrency,
924                                                        createStreamingResultSet(), true,
925                                                        this.currentCatalog, (cachedMetaData == null));
926                                } else {
927                                        if (this.maxRows <= 0) {
928                                                this.connection
929                                                                .execSQL(
930                                                                                this,
931                                                                                "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
932                                                                                java.sql.ResultSet.TYPE_FORWARD_ONLY,
933                                                                                java.sql.ResultSet.CONCUR_READ_ONLY,
934                                                                                false, false, this.currentCatalog, true); //$NON-NLS-1$
935                                        } else {
936                                                this.connection
937                                                                .execSQL(
938                                                                                this,
939                                                                                "SET OPTION SQL_SELECT_LIMIT=" + this.maxRows, -1, //$NON-NLS-1$
940                                                                                null,
941                                                                                java.sql.ResultSet.TYPE_FORWARD_ONLY,
942                                                                                java.sql.ResultSet.CONCUR_READ_ONLY,
943                                                                                false, false, this.currentCatalog, true); //$NON-NLS-1$
944                                        }
945 
946                                        this.results = this.connection.execSQL(this, sql, -1, null,
947                                                        this.resultSetType, this.resultSetConcurrency,
948                                                        createStreamingResultSet(), true,
949                                                        this.currentCatalog, (cachedMetaData == null));
950 
951                                        if (oldCatalog != null) {
952                                                this.connection.setCatalog(oldCatalog);
953                                        }
954                                }
955                        } else {
956                                this.results = this.connection.execSQL(this, sql, -1, null,
957                                                this.resultSetType, this.resultSetConcurrency,
958                                                createStreamingResultSet(), true, this.currentCatalog,
959                                                (cachedMetaData == null));
960                        }
961 
962                        if (oldCatalog != null) {
963                                this.connection.setCatalog(oldCatalog);
964                        }
965                }
966 
967                this.lastInsertId = this.results.getUpdateID();
968 
969                /*
970                 * if (!this.results.reallyResult()) { if
971                 * (!this.connection.getAutoCommit()) { this.connection.rollback(); }
972                 * 
973                 * throw new SQLException(Messages.getString("Statement.40"),
974                 * //$NON-NLS-1$ SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ }
975                 */
976                if (cachedMetaData != null) {
977                        initializeResultsMetadataFromCache(sql, cachedMetaData,
978                                        this.results);
979                } else {
980                        if (this.connection.getCacheResultSetMetadata()) {
981                                initializeResultsMetadataFromCache(sql,
982                                                null /* will be created */, this.results);
983                        }
984                }
985 
986                return this.results;
987        }
988 
989        /**
990         * Execute a SQL INSERT, UPDATE or DELETE statement. In addition SQL
991         * statements that return nothing such as SQL DDL statements can be executed
992         * Any IDs generated for AUTO_INCREMENT fields can be retrieved by casting
993         * this Statement to org.gjt.mm.mysql.Statement and calling the
994         * getLastInsertID() method.
995         * 
996         * @param sql
997         *            a SQL statement
998         * 
999         * @return either a row count, or 0 for SQL commands
1000         * 
1001         * @exception SQLException
1002         *                if a database access error occurs
1003         */
1004        public synchronized int executeUpdate(String sql) throws SQLException {
1005                return executeUpdate(sql, false);
1006        }
1007        
1008        protected synchronized int executeUpdate(String sql, boolean isBatch) throws SQLException {
1009                checkNullOrEmptyQuery(sql);
1010 
1011                checkClosed();
1012 
1013                if (this.connection.isReadOnly()) {
1014                        throw new SQLException(Messages.getString("Statement.42") //$NON-NLS-1$
1015                                        + Messages.getString("Statement.43"), //$NON-NLS-1$
1016                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1017                }
1018 
1019                if (StringUtils.startsWithIgnoreCaseAndWs(sql, "select")) { //$NON-NLS-1$
1020                        throw new SQLException(Messages.getString("Statement.46"), //$NON-NLS-1$
1021                                        "01S03"); //$NON-NLS-1$
1022                }
1023 
1024                char firstStatementChar = StringUtils.firstNonWsCharUc(sql);
1025 
1026                if (this.doEscapeProcessing) {
1027                        Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
1028                                        this.connection.serverSupportsConvertFn());
1029 
1030                        if (escapedSqlResult instanceof String) {
1031                                sql = (String) escapedSqlResult;
1032                        } else {
1033                                sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
1034                        }
1035                }
1036 
1037                if (this.results != null) {
1038                        if (!this.connection.getHoldResultsOpenOverStatementClose()) {
1039                                this.results.realClose(false);
1040                        }
1041                }
1042 
1043                // The checking and changing of catalogs
1044                // must happen in sequence, so synchronize
1045                // on the same mutex that _conn is using
1046                ResultSet rs = null;
1047 
1048                synchronized (this.connection.getMutex()) {
1049                        if (!isBatch) {
1050                                this.batchedGeneratedKeys = null;
1051                        }
1052                        
1053                        String oldCatalog = null;
1054 
1055                        if (!this.connection.getCatalog().equals(this.currentCatalog)) {
1056                                oldCatalog = this.connection.getCatalog();
1057                                this.connection.setCatalog(this.currentCatalog);
1058                        }
1059 
1060                        //
1061                        // Only apply max_rows to selects
1062                        //
1063                        if (this.connection.useMaxRows()) {
1064                                this.connection.execSQL(this,
1065                                                "SET OPTION SQL_SELECT_LIMIT=DEFAULT", //$NON-NLS-1$
1066                                                -1, null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
1067                                                java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
1068                                                this.currentCatalog, true);
1069                        }
1070 
1071                        rs = this.connection
1072                                        .execSQL(this, sql, -1, null,
1073                                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
1074                                                        java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
1075                                                        this.currentCatalog, true /* force read of field info on DML */, 
1076                                                        USES_VARIABLES_FALSE, 
1077                                                        isBatch);
1078 
1079                        if (oldCatalog != null) {
1080                                this.connection.setCatalog(oldCatalog);
1081                        }
1082                }
1083 
1084                this.results = rs;
1085 
1086                rs.setFirstCharOfQuery(firstStatementChar);
1087 
1088                this.updateCount = rs.getUpdateCount();
1089 
1090                int truncatedUpdateCount = 0;
1091 
1092                if (this.updateCount > Integer.MAX_VALUE) {
1093                        truncatedUpdateCount = Integer.MAX_VALUE;
1094                } else {
1095                        truncatedUpdateCount = (int) this.updateCount;
1096                }
1097 
1098                this.lastInsertId = rs.getUpdateID();
1099 
1100                return truncatedUpdateCount;
1101        }
1102 
1103        /**
1104         * @see Statement#executeUpdate(String, int)
1105         */
1106        public int executeUpdate(String sql, int returnGeneratedKeys)
1107                        throws SQLException {
1108                if (returnGeneratedKeys == java.sql.Statement.RETURN_GENERATED_KEYS) {
1109                        checkClosed();
1110 
1111                        synchronized (this.connection.getMutex()) {
1112                                // If this is a 'REPLACE' query, we need to be able to parse
1113                                // the 'info' message returned from the server to determine
1114                                // the actual number of keys generated.
1115                                boolean readInfoMsgState = this.connection
1116                                                .isReadInfoMsgEnabled();
1117                                this.connection.setReadInfoMsgEnabled(true);
1118 
1119                                try {
1120                                        return executeUpdate(sql);
1121                                } finally {
1122                                        this.connection.setReadInfoMsgEnabled(readInfoMsgState);
1123                                }
1124                        }
1125                }
1126 
1127                return executeUpdate(sql);
1128        }
1129 
1130        /**
1131         * @see Statement#executeUpdate(String, int[])
1132         */
1133        public int executeUpdate(String sql, int[] generatedKeyIndices)
1134                        throws SQLException {
1135                if ((generatedKeyIndices != null) && (generatedKeyIndices.length > 0)) {
1136                        checkClosed();
1137 
1138                        synchronized (this.connection.getMutex()) {
1139                                // If this is a 'REPLACE' query, we need to be able to parse
1140                                // the 'info' message returned from the server to determine
1141                                // the actual number of keys generated.
1142                                boolean readInfoMsgState = this.connection
1143                                                .isReadInfoMsgEnabled();
1144                                this.connection.setReadInfoMsgEnabled(true);
1145 
1146                                try {
1147                                        return executeUpdate(sql);
1148                                } finally {
1149                                        this.connection.setReadInfoMsgEnabled(readInfoMsgState);
1150                                }
1151                        }
1152                }
1153 
1154                return executeUpdate(sql);
1155        }
1156 
1157        /**
1158         * @see Statement#executeUpdate(String, String[])
1159         */
1160        public int executeUpdate(String sql, String[] generatedKeyNames)
1161                        throws SQLException {
1162                if ((generatedKeyNames != null) && (generatedKeyNames.length > 0)) {
1163                        checkClosed();
1164 
1165                        synchronized (this.connection.getMutex()) {
1166                                // If this is a 'REPLACE' query, we need to be able to parse
1167                                // the 'info' message returned from the server to determine
1168                                // the actual number of keys generated.
1169                                boolean readInfoMsgState = this.connection
1170                                                .isReadInfoMsgEnabled();
1171                                this.connection.setReadInfoMsgEnabled(true);
1172 
1173                                try {
1174                                        return executeUpdate(sql);
1175                                } finally {
1176                                        this.connection.setReadInfoMsgEnabled(readInfoMsgState);
1177                                }
1178                        }
1179                }
1180 
1181                return executeUpdate(sql);
1182        }
1183 
1184        /**
1185         * Required by JDBC spec
1186         */
1187        /*
1188        protected void finalize() throws Throwable {
1189                if (!this.isClosed) {
1190                        realClose(false);
1191                }
1192        }
1193*/
1194        
1195        /**
1196         * Returns cached metadata (or null if not cached) for the given query,
1197         * which must match _exactly_. Note this method is guarded against
1198         * concurrent access via the synchronized{} block in execute() and
1199         * executeQuery().
1200         * 
1201         * @param sql
1202         *            the query that is the key to the cache
1203         * 
1204         * @return DOCUMENT ME!
1205         */
1206        protected CachedResultSetMetaData getCachedMetaData(String sql) {
1207                if (this.resultSetMetadataCache != null) {
1208                        return (CachedResultSetMetaData) this.resultSetMetadataCache
1209                                        .get(sql);
1210                }
1211 
1212                return null; // no cache exists (yet)
1213        }
1214 
1215        /**
1216         * JDBC 2.0 Return the Connection that produced the Statement.
1217         * 
1218         * @return the Connection that produced the Statement
1219         * 
1220         * @throws SQLException
1221         *             if an error occurs
1222         */
1223        public synchronized java.sql.Connection getConnection() throws SQLException {
1224                return this.connection;
1225        }
1226 
1227        /**
1228         * JDBC 2.0 Determine the fetch direction.
1229         * 
1230         * @return the default fetch direction
1231         * 
1232         * @exception SQLException
1233         *                if a database-access error occurs
1234         */
1235        public int getFetchDirection() throws SQLException {
1236                return java.sql.ResultSet.FETCH_FORWARD;
1237        }
1238 
1239        /**
1240         * JDBC 2.0 Determine the default fetch size.
1241         * 
1242         * @return the number of rows to fetch at a time
1243         * 
1244         * @throws SQLException
1245         *             if an error occurs
1246         */
1247        public synchronized int getFetchSize() throws SQLException {
1248                return this.fetchSize;
1249        }
1250 
1251        /**
1252         * DOCUMENT ME!
1253         * 
1254         * @return DOCUMENT ME!
1255         * 
1256         * @throws SQLException
1257         *             DOCUMENT ME!
1258         */
1259        public synchronized java.sql.ResultSet getGeneratedKeys()
1260                        throws SQLException {
1261                if (this.batchedGeneratedKeys == null) {
1262                        return getGeneratedKeysInternal();
1263                }
1264 
1265                Field[] fields = new Field[1];
1266                fields[0] = new Field("", "GENERATED_KEY", Types.BIGINT, 17); //$NON-NLS-1$ //$NON-NLS-2$
1267                fields[0].setConnection(this.connection);
1268 
1269                return new com.mysql.jdbc.ResultSet(this.currentCatalog, fields,
1270                                new RowDataStatic(this.batchedGeneratedKeys), this.connection,
1271                                this);
1272        }
1273 
1274        /*
1275         * Needed because there's no concept of super.super to get to this
1276         * implementation from ServerPreparedStatement when dealing with batched
1277         * updates.
1278         */
1279        protected synchronized java.sql.ResultSet getGeneratedKeysInternal()
1280                        throws SQLException {
1281                Field[] fields = new Field[1];
1282                fields[0] = new Field("", "GENERATED_KEY", Types.BIGINT, 17); //$NON-NLS-1$ //$NON-NLS-2$
1283                fields[0].setConnection(this.connection);
1284                
1285                ArrayList rowSet = new ArrayList();
1286 
1287                long beginAt = getLastInsertID();
1288                int numKeys = getUpdateCount();
1289 
1290                if (this.results != null) {
1291                        String serverInfo = this.results.getServerInfo();
1292        
1293                        // 
1294                        // Only parse server info messages for 'REPLACE'
1295                        // queries
1296                        //
1297                        if ((numKeys > 0) && (this.results.getFirstCharOfQuery() == 'R')
1298                                        && (serverInfo != null) && (serverInfo.length() > 0)) {
1299                                numKeys = getRecordCountFromInfo(serverInfo);
1300                        }
1301        
1302                        if ((beginAt > 0) && (numKeys > 0)) {
1303                                for (int i = 0; i < numKeys; i++) {
1304                                        byte[][] row = new byte[1][];
1305                                        row[0] = Long.toString(beginAt++).getBytes();
1306                                        rowSet.add(row);
1307                                }
1308                        }
1309                }
1310 
1311                return new com.mysql.jdbc.ResultSet(this.currentCatalog, fields,
1312                                new RowDataStatic(rowSet), this.connection, this);
1313        }
1314 
1315        /**
1316         * Returns the id used when profiling
1317         * 
1318         * @return the id used when profiling.
1319         */
1320        protected int getId() {
1321                return this.statementId;
1322        }
1323 
1324        /**
1325         * getLastInsertID returns the value of the auto_incremented key after an
1326         * executeQuery() or excute() call.
1327         * 
1328         * <p>
1329         * This gets around the un-threadsafe behavior of "select LAST_INSERT_ID()"
1330         * which is tied to the Connection that created this Statement, and
1331         * therefore could have had many INSERTS performed before one gets a chance
1332         * to call "select LAST_INSERT_ID()".
1333         * </p>
1334         * 
1335         * @return the last update ID.
1336         */
1337        public synchronized long getLastInsertID() {
1338                return this.lastInsertId;
1339        }
1340 
1341        /**
1342         * getLongUpdateCount returns the current result as an update count, if the
1343         * result is a ResultSet or there are no more results, -1 is returned. It
1344         * should only be called once per result.
1345         * 
1346         * <p>
1347         * This method returns longs as MySQL server versions newer than 3.22.4
1348         * return 64-bit values for update counts
1349         * </p>
1350         * 
1351         * @return the current update count.
1352         */
1353        public synchronized long getLongUpdateCount() {
1354                if (this.results == null) {
1355                        return -1;
1356                }
1357 
1358                if (this.results.reallyResult()) {
1359                        return -1;
1360                }
1361 
1362                return this.updateCount;
1363        }
1364 
1365        /**
1366         * The maxFieldSize limit (in bytes) is the maximum amount of data returned
1367         * for any column value; it only applies to BINARY, VARBINARY,
1368         * LONGVARBINARY, CHAR, VARCHAR and LONGVARCHAR columns. If the limit is
1369         * exceeded, the excess data is silently discarded.
1370         * 
1371         * @return the current max column size limit; zero means unlimited
1372         * 
1373         * @exception SQLException
1374         *                if a database access error occurs
1375         */
1376        public synchronized int getMaxFieldSize() throws SQLException {
1377                return this.maxFieldSize;
1378        }
1379 
1380        /**
1381         * The maxRows limit is set to limit the number of rows that any ResultSet
1382         * can contain. If the limit is exceeded, the excess rows are silently
1383         * dropped.
1384         * 
1385         * @return the current maximum row limit; zero means unlimited
1386         * 
1387         * @exception SQLException
1388         *                if a database access error occurs
1389         */
1390        public synchronized int getMaxRows() throws SQLException {
1391                if (this.maxRows <= 0) {
1392                        return 0;
1393                }
1394 
1395                return this.maxRows;
1396        }
1397 
1398        /**
1399         * getMoreResults moves to a Statement's next result. If it returns true,
1400         * this result is a ResulSet.
1401         * 
1402         * @return true if the next ResultSet is valid
1403         * 
1404         * @exception SQLException
1405         *                if a database access error occurs
1406         */
1407        public boolean getMoreResults() throws SQLException {
1408                return getMoreResults(CLOSE_CURRENT_RESULT);
1409        }
1410 
1411        /**
1412         * @see Statement#getMoreResults(int)
1413         */
1414        public synchronized boolean getMoreResults(int current) throws SQLException {
1415 
1416                if (this.results == null) {
1417                        return false;
1418                }
1419 
1420                ResultSet nextResultSet = this.results.getNextResultSet();
1421 
1422                switch (current) {
1423                case java.sql.Statement.CLOSE_CURRENT_RESULT:
1424 
1425                        if (this.results != null) {
1426                                this.results.close();
1427                                this.results.clearNextResult();
1428                        }
1429 
1430                        break;
1431 
1432                case java.sql.Statement.CLOSE_ALL_RESULTS:
1433 
1434                        if (this.results != null) {
1435                                this.results.close();
1436                                this.results.clearNextResult();
1437                        }
1438 
1439                        closeAllOpenResults();
1440 
1441                        break;
1442 
1443                case java.sql.Statement.KEEP_CURRENT_RESULT:
1444                        if (!this.connection.getDontTrackOpenResources()) {
1445                                this.openResults.add(this.results);
1446                        }
1447 
1448                        this.results.clearNextResult(); // nobody besides us should
1449                        // ever need this value...
1450                        break;
1451 
1452                default:
1453                        throw new SQLException(Messages.getString("Statement.19"), //$NON-NLS-1$
1454                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1455                }
1456 
1457                this.results = nextResultSet;
1458 
1459                if (this.results == null) {
1460                        this.updateCount = -1;
1461                        this.lastInsertId = -1;
1462                } else if (this.results.reallyResult()) {
1463                        this.updateCount = -1;
1464                        this.lastInsertId = -1;
1465                } else {
1466                        this.updateCount = this.results.getUpdateCount();
1467                        this.lastInsertId = this.results.getUpdateID();
1468                }
1469 
1470                return ((this.results != null) && this.results.reallyResult()) ? true
1471                                : false;
1472        }
1473 
1474        /**
1475         * The queryTimeout limit is the number of seconds the driver will wait for
1476         * a Statement to execute. If the limit is exceeded, a SQLException is
1477         * thrown.
1478         * 
1479         * @return the current query timeout limit in seconds; 0 = unlimited
1480         * 
1481         * @exception SQLException
1482         *                if a database access error occurs
1483         */
1484        public int getQueryTimeout() throws SQLException {
1485                return this.timeout;
1486        }
1487 
1488        /**
1489         * Parses actual record count from 'info' message
1490         * 
1491         * @param serverInfo
1492         *            DOCUMENT ME!
1493         * 
1494         * @return DOCUMENT ME!
1495         */
1496        private int getRecordCountFromInfo(String serverInfo) {
1497                StringBuffer recordsBuf = new StringBuffer();
1498                int recordsCount = 0;
1499                int duplicatesCount = 0;
1500 
1501                char c = (char) 0;
1502 
1503                int length = serverInfo.length();
1504                int i = 0;
1505 
1506                for (; i < length; i++) {
1507                        c = serverInfo.charAt(i);
1508 
1509                        if (Character.isDigit(c)) {
1510                                break;
1511                        }
1512                }
1513 
1514                recordsBuf.append(c);
1515                i++;
1516 
1517                for (; i < length; i++) {
1518                        c = serverInfo.charAt(i);
1519 
1520                        if (!Character.isDigit(c)) {
1521                                break;
1522                        }
1523 
1524                        recordsBuf.append(c);
1525                }
1526 
1527                recordsCount = Integer.parseInt(recordsBuf.toString());
1528 
1529                StringBuffer duplicatesBuf = new StringBuffer();
1530 
1531                for (; i < length; i++) {
1532                        c = serverInfo.charAt(i);
1533 
1534                        if (Character.isDigit(c)) {
1535                                break;
1536                        }
1537                }
1538 
1539                duplicatesBuf.append(c);
1540                i++;
1541 
1542                for (; i < length; i++) {
1543                        c = serverInfo.charAt(i);
1544 
1545                        if (!Character.isDigit(c)) {
1546                                break;
1547                        }
1548 
1549                        duplicatesBuf.append(c);
1550                }
1551 
1552                duplicatesCount = Integer.parseInt(duplicatesBuf.toString());
1553 
1554                return recordsCount - duplicatesCount;
1555        }
1556 
1557        /**
1558         * getResultSet returns the current result as a ResultSet. It should only be
1559         * called once per result.
1560         * 
1561         * @return the current result set; null if there are no more
1562         * 
1563         * @exception SQLException
1564         *                if a database access error occurs (why?)
1565         */
1566        public synchronized java.sql.ResultSet getResultSet() throws SQLException {
1567                return ((this.results != null) && this.results.reallyResult()) ? (java.sql.ResultSet) this.results
1568                                : null;
1569        }
1570 
1571        /**
1572         * JDBC 2.0 Determine the result set concurrency.
1573         * 
1574         * @return CONCUR_UPDATABLE or CONCUR_READONLY
1575         * 
1576         * @throws SQLException
1577         *             if an error occurs
1578         */
1579        public synchronized int getResultSetConcurrency() throws SQLException {
1580                return this.resultSetConcurrency;
1581        }
1582 
1583        /**
1584         * @see Statement#getResultSetHoldability()
1585         */
1586        public int getResultSetHoldability() throws SQLException {
1587                return java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
1588        }
1589 
1590        /**
1591         * JDBC 2.0 Determine the result set type.
1592         * 
1593         * @return the ResultSet type (SCROLL_SENSITIVE or SCROLL_INSENSITIVE)
1594         * 
1595         * @throws SQLException
1596         *             if an error occurs.
1597         */
1598        public synchronized int getResultSetType() throws SQLException {
1599                return this.resultSetType;
1600        }
1601 
1602        /**
1603         * getUpdateCount returns the current result as an update count, if the
1604         * result is a ResultSet or there are no more results, -1 is returned. It
1605         * should only be called once per result.
1606         * 
1607         * @return the current result as an update count.
1608         * 
1609         * @exception SQLException
1610         *                if a database access error occurs
1611         */
1612        public synchronized int getUpdateCount() throws SQLException {
1613                if (this.results == null) {
1614                        return -1;
1615                }
1616 
1617                if (this.results.reallyResult()) {
1618                        return -1;
1619                }
1620 
1621                int truncatedUpdateCount = 0;
1622 
1623                if (this.results.getUpdateCount() > Integer.MAX_VALUE) {
1624                        truncatedUpdateCount = Integer.MAX_VALUE;
1625                } else {
1626                        truncatedUpdateCount = (int) this.results.getUpdateCount();
1627                }
1628 
1629                return truncatedUpdateCount;
1630        }
1631 
1632        /**
1633         * The first warning reported by calls on this Statement is returned. A
1634         * Statement's execute methods clear its java.sql.SQLWarning chain.
1635         * Subsequent Statement warnings will be chained to this
1636         * java.sql.SQLWarning.
1637         * 
1638         * <p>
1639         * The Warning chain is automatically cleared each time a statement is
1640         * (re)executed.
1641         * </p>
1642         * 
1643         * <p>
1644         * <B>Note:</B> If you are processing a ResultSet then any warnings
1645         * associated with ResultSet reads will be chained on the ResultSet object.
1646         * </p>
1647         * 
1648         * @return the first java.sql.SQLWarning or null
1649         * 
1650         * @exception SQLException
1651         *                if a database access error occurs
1652         */
1653        public synchronized java.sql.SQLWarning getWarnings() throws SQLException {
1654                checkClosed();
1655                
1656                if (this.connection.versionMeetsMinimum(4, 1, 0)) {
1657                        SQLWarning pendingWarningsFromServer = SQLError
1658                                        .convertShowWarningsToSQLWarnings(this.connection);
1659 
1660                        if (this.warningChain != null) {
1661                                this.warningChain.setNextWarning(pendingWarningsFromServer);
1662                        } else {
1663                                this.warningChain = pendingWarningsFromServer;
1664                        }
1665 
1666                        return this.warningChain;
1667                }
1668 
1669                return this.warningChain;
1670        }
1671 
1672        /**
1673         * Caches CachedResultSetMetaData that has been placed in the cache using
1674         * the given SQL as a key.
1675         * 
1676         * @param sql
1677         *            DOCUMENT ME!
1678         * @param cachedMetaData
1679         *            DOCUMENT ME!
1680         * @param resultSet
1681         *            DOCUMENT ME!
1682         * 
1683         * @throws SQLException
1684         *             DOCUMENT ME!
1685         */
1686        protected void initializeResultsMetadataFromCache(String sql,
1687                        CachedResultSetMetaData cachedMetaData, ResultSet resultSet)
1688                        throws SQLException {
1689                synchronized (resultSet) {
1690                        if (cachedMetaData == null) {
1691                                // read from results
1692                                cachedMetaData = new CachedResultSetMetaData();
1693                                cachedMetaData.fields = this.results.fields;
1694 
1695                                // assume that users will use named-based
1696                                // lookups
1697                                resultSet.buildIndexMapping();
1698 
1699                                cachedMetaData.columnNameToIndex = resultSet.columnNameToIndex;
1700                                cachedMetaData.fullColumnNameToIndex = resultSet.fullColumnNameToIndex;
1701 
1702                                cachedMetaData.metadata = resultSet.getMetaData();
1703 
1704                                if (this.resultSetMetadataCache == null) {
1705                                        this.resultSetMetadataCache = new LRUCache(this.connection
1706                                                        .getMetadataCacheSize());
1707                                }
1708 
1709                                this.resultSetMetadataCache.put(sql, cachedMetaData);
1710                        } else {
1711                                // initialize results from cached data
1712                                resultSet.fields = cachedMetaData.fields;
1713                                resultSet.columnNameToIndex = cachedMetaData.columnNameToIndex;
1714                                resultSet.fullColumnNameToIndex = cachedMetaData.fullColumnNameToIndex;
1715                                resultSet.hasBuiltIndexMapping = true;
1716 
1717                                // results.resultSetMetaData = cachedMetaData.metadata;
1718                        }
1719                }
1720        }
1721 
1722        /**
1723         * Closes this statement, and frees resources.
1724         * 
1725         * @param calledExplicitly
1726         *            was this called from close()?
1727         * 
1728         * @throws SQLException
1729         *             if an error occurs
1730         */
1731        protected synchronized void realClose(boolean calledExplicitly) throws SQLException {
1732                if (this.isClosed) {
1733                        return;
1734                }
1735 
1736                if (this.useUsageAdvisor) {
1737                        if (!calledExplicitly) {
1738                                String message = Messages.getString("Statement.63") //$NON-NLS-1$
1739                                                + Messages.getString("Statement.64"); //$NON-NLS-1$
1740 
1741                                this.eventSink.consumeEvent(new ProfilerEvent(
1742                                                ProfilerEvent.TYPE_WARN, "", //$NON-NLS-1$
1743                                                this.currentCatalog, this.connection.getId(), this
1744                                                                .getId(), -1, System.currentTimeMillis(), 0,
1745                                                null, this.pointOfOrigin, message));
1746                        }
1747                }
1748 
1749                if (this.connection != null) {
1750                        synchronized (this.connection) {
1751                                if (this.results != null) {
1752                                        if (!this.connection.getHoldResultsOpenOverStatementClose()) {
1753                                                try {
1754                                                        this.results.close();
1755                                                } catch (Exception ex) {
1756                                                        ;
1757                                                }
1758                                        }
1759                                }
1760                                        
1761                                if (this.maxRowsChanged) {
1762                                        this.connection.unsetMaxRows(this);
1763                                }
1764        
1765                                if (!this.connection.getDontTrackOpenResources()) {
1766                                        this.connection.unregisterStatement(this);
1767                                }
1768                        }
1769                }
1770 
1771                this.closeAllOpenResults();
1772 
1773                this.results = null;
1774                this.connection = null;
1775                this.warningChain = null;
1776                this.openResults = null;
1777                this.batchedGeneratedKeys = null;
1778                this.isClosed = true;
1779        }
1780 
1781        /**
1782         * setCursorName defines the SQL cursor name that will be used by subsequent
1783         * execute methods. This name can then be used in SQL positioned
1784         * update/delete statements to identify the current row in the ResultSet
1785         * generated by this statement. If a database doesn't support positioned
1786         * update/delete, this method is a no-op.
1787         * 
1788         * <p>
1789         * <b>Note:</b> This MySQL driver does not support cursors.
1790         * </p>
1791         * 
1792         * @param name
1793         *            the new cursor name
1794         * 
1795         * @exception SQLException
1796         *                if a database access error occurs
1797         */
1798        public void setCursorName(String name) throws SQLException {
1799                // No-op
1800        }
1801 
1802        /**
1803         * If escape scanning is on (the default), the driver will do escape
1804         * substitution before sending the SQL to the database.
1805         * 
1806         * @param enable
1807         *            true to enable; false to disable
1808         * 
1809         * @exception SQLException
1810         *                if a database access error occurs
1811         */
1812        public synchronized void setEscapeProcessing(boolean enable)
1813                        throws SQLException {
1814                this.doEscapeProcessing = enable;
1815        }
1816 
1817        /**
1818         * JDBC 2.0 Give a hint as to the direction in which the rows in a result
1819         * set will be processed. The hint applies only to result sets created using
1820         * this Statement object. The default value is ResultSet.FETCH_FORWARD.
1821         * 
1822         * @param direction
1823         *            the initial direction for processing rows
1824         * 
1825         * @exception SQLException
1826         *                if a database-access error occurs or direction is not one
1827         *                of ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, or
1828         *                ResultSet.FETCH_UNKNOWN
1829         */
1830        public void setFetchDirection(int direction) throws SQLException {
1831                switch (direction) {
1832                case java.sql.ResultSet.FETCH_FORWARD:
1833                case java.sql.ResultSet.FETCH_REVERSE:
1834                case java.sql.ResultSet.FETCH_UNKNOWN:
1835                        break;
1836 
1837                default:
1838                        throw new SQLException(Messages.getString("Statement.5"), //$NON-NLS-1$
1839                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1840                }
1841        }
1842 
1843        /**
1844         * JDBC 2.0 Give the JDBC driver a hint as to the number of rows that should
1845         * be fetched from the database when more rows are needed. The number of
1846         * rows specified only affects result sets created using this statement. If
1847         * the value specified is zero, then the hint is ignored. The default value
1848         * is zero.
1849         * 
1850         * @param rows
1851         *            the number of rows to fetch
1852         * 
1853         * @exception SQLException
1854         *                if a database-access error occurs, or the condition 0
1855         *                &lt;= rows &lt;= this.getMaxRows() is not satisfied.
1856         */
1857        public synchronized void setFetchSize(int rows) throws SQLException {
1858                if (((rows < 0) && (rows != Integer.MIN_VALUE))
1859                                || ((this.maxRows != 0) && (this.maxRows != -1) && (rows > this
1860                                                .getMaxRows()))) {
1861                        throw new SQLException(Messages.getString("Statement.7"), //$NON-NLS-1$
1862                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
1863                }
1864 
1865                this.fetchSize = rows;
1866        }
1867 
1868        /**
1869         * Sets the maxFieldSize
1870         * 
1871         * @param max
1872         *            the new max column size limit; zero means unlimited
1873         * 
1874         * @exception SQLException
1875         *                if size exceeds buffer size
1876         */
1877        public synchronized void setMaxFieldSize(int max) throws SQLException {
1878                if (max < 0) {
1879                        throw new SQLException(Messages.getString("Statement.11"), //$NON-NLS-1$
1880                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1881                }
1882 
1883                int maxBuf = (this.connection != null) ? this.connection
1884                                .getMaxAllowedPacket() : MysqlIO.getMaxBuf();
1885 
1886                if (max > maxBuf) {
1887                        throw new SQLException(Messages.getString("Statement.13", //$NON-NLS-1$
1888                                        new Object[] { new Long(maxBuf) }), //$NON-NLS-1$
1889                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1890                }
1891 
1892                this.maxFieldSize = max;
1893        }
1894 
1895        /**
1896         * Set the maximum number of rows
1897         * 
1898         * @param max
1899         *            the new max rows limit; zero means unlimited
1900         * 
1901         * @exception SQLException
1902         *                if a database access error occurs
1903         * 
1904         * @see getMaxRows
1905         */
1906        public synchronized void setMaxRows(int max) throws SQLException {
1907                if ((max > MysqlDefs.MAX_ROWS) || (max < 0)) {
1908                        throw new SQLException(
1909                                        Messages.getString("Statement.15") + max //$NON-NLS-1$
1910                                                        + " > " //$NON-NLS-1$ //$NON-NLS-2$
1911                                                        + MysqlDefs.MAX_ROWS + ".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
1912                }
1913 
1914                if (max == 0) {
1915                        max = -1;
1916                }
1917 
1918                this.maxRows = max;
1919                this.maxRowsChanged = true;
1920 
1921                if (this.maxRows == -1) {
1922                        this.connection.unsetMaxRows(this);
1923                        this.maxRowsChanged = false;
1924                } else {
1925                        // Most people don't use setMaxRows()
1926                        // so don't penalize them
1927                        // with the extra query it takes
1928                        // to do it efficiently unless we need
1929                        // to.
1930                        this.connection.maxRowsChanged(this);
1931                }
1932        }
1933 
1934        /**
1935         * Sets the queryTimeout limit
1936         * 
1937         * @param seconds -
1938         *            the new query timeout limit in seconds
1939         * 
1940         * @exception SQLException
1941         *                if a database access error occurs
1942         */
1943        public void setQueryTimeout(int seconds) throws SQLException {
1944                if (seconds < 0) {
1945                        throw new SQLException(Messages.getString("Statement.21"), //$NON-NLS-1$
1946                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1947                }
1948 
1949                this.timeout = seconds;
1950        }
1951 
1952        /**
1953         * Sets the concurrency for result sets generated by this statement
1954         * 
1955         * @param concurrencyFlag
1956         *            DOCUMENT ME!
1957         */
1958        synchronized void setResultSetConcurrency(int concurrencyFlag) {
1959                this.resultSetConcurrency = concurrencyFlag;
1960        }
1961 
1962        /**
1963         * Sets the result set type for result sets generated by this statement
1964         * 
1965         * @param typeFlag
1966         *            DOCUMENT ME!
1967         */
1968        synchronized void setResultSetType(int typeFlag) {
1969                this.resultSetType = typeFlag;
1970        }
1971 
1972        protected void getBatchedGeneratedKeys(java.sql.Statement batchedStatement) throws SQLException {
1973                if (this.retrieveGeneratedKeys) {
1974                        java.sql.ResultSet rs = null;
1975        
1976                        try {
1977                                rs = batchedStatement.getGeneratedKeys();
1978        
1979                                while (rs.next()) {
1980                                        this.batchedGeneratedKeys
1981                                                        .add(new byte[][] { rs.getBytes(1) });
1982                                }
1983                        } finally {
1984                                if (rs != null) {
1985                                        rs.close();
1986                                }
1987                        }
1988                }
1989        }
1990        
1991        protected void getBatchedGeneratedKeys() throws SQLException {
1992                if (this.retrieveGeneratedKeys) {
1993                        java.sql.ResultSet rs = null;
1994        
1995                        try {
1996                                rs = getGeneratedKeysInternal();
1997        
1998                                while (rs.next()) {
1999                                        this.batchedGeneratedKeys
2000                                                        .add(new byte[][] { rs.getBytes(1) });
2001                                }
2002                        } finally {
2003                                if (rs != null) {
2004                                        rs.close();
2005                                }
2006                        }
2007                }
2008        }
2009 
2010}

[all classes][com.mysql.jdbc]
EMMA 2.0.4217 (C) Vladimir Roubtsov