EMMA Coverage Report (generated Mon Jul 24 20:33:06 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [Statement.java]

nameclass, %method, %block, %line, %
Statement.java75%  (3/4)86%  (59/69)76%  (2313/3063)77%  (533.2/693)

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 Statement$1100% (1/1)100% (2/2)68%  (52/77)73%  (15.2/21)
run (): void 100% (1/1)65%  (46/71)71%  (14.2/20)
Statement$1 (Statement$CancelTask): void 100% (1/1)100% (6/6)100% (1/1)
     
class Statement100% (1/1)86%  (55/64)76%  (2238/2951)77%  (510.9/662)
createResultSetUsingServerFetch (String): ResultSet 0%   (0/1)0%   (0/29)0%   (0/7)
execute (String, String []): boolean 0%   (0/1)0%   (0/48)0%   (0/10)
execute (String, int []): boolean 0%   (0/1)0%   (0/47)0%   (0/10)
executeUpdate (String, String []): int 0%   (0/1)0%   (0/48)0%   (0/10)
executeUpdate (String, int []): int 0%   (0/1)0%   (0/47)0%   (0/10)
getCachedMetaData (String): Statement$CachedResultSetMetaData 0%   (0/1)0%   (0/11)0%   (0/3)
getLongUpdateCount (): long 0%   (0/1)0%   (0/14)0%   (0/5)
getResultSetInternal (): ResultSet 0%   (0/1)0%   (0/3)0%   (0/1)
initializeResultsMetadataFromCache (String, Statement$CachedResultSetMetaData... 0%   (0/1)0%   (0/72)0%   (0/17)
checkNullOrEmptyQuery (String): void 100% (1/1)38%  (6/16)60%  (3/5)
useServerFetch (): boolean 100% (1/1)47%  (9/19)47%  (0.5/1)
closeAllOpenResults (): void 100% (1/1)54%  (14/26)44%  (4/9)
getCalendarInstanceForSessionOrNew (): Calendar 100% (1/1)64%  (7/11)67%  (2/3)
getMoreResults (int): boolean 100% (1/1)66%  (64/97)59%  (16/27)
executeUpdate (String, int): int 100% (1/1)67%  (30/45)78%  (7.8/10)
execute (String, int): boolean 100% (1/1)67%  (31/46)78%  (7.8/10)
executeUpdate (String, boolean): int 100% (1/1)72%  (157/219)75%  (37.7/50)
execute (String): boolean 100% (1/1)74%  (244/328)82%  (55.1/67)
executeQuery (String): ResultSet 100% (1/1)76%  (227/300)74%  (41.5/56)
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)
getWarnings (): SQLWarning 100% (1/1)86%  (32/37)88%  (7/8)
getRecordCountFromInfo (String): int 100% (1/1)88%  (89/101)90%  (28.7/32)
getUpdateCount (): int 100% (1/1)90%  (26/29)89%  (8/9)
cancel (): void 100% (1/1)93%  (54/58)96%  (13.4/14)
executeBatch (): int [] 100% (1/1)93%  (186/199)97%  (37/38)
executeBatchUsingMultiQueries (boolean, int): int [] 100% (1/1)94%  (241/256)94%  (47.8/51)
Statement (Connection, String): void 100% (1/1)96%  (202/210)96%  (54/56)
setMaxFieldSize (int): void 100% (1/1)97%  (37/38)99%  (6.9/7)
realClose (boolean, 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% (9/9)100% (3/3)
checkForDml (String, char): void 100% (1/1)100% (45/45)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% (5/5)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% (9/9)100% (4/4)
setFetchSize (int): void 100% (1/1)100% (25/25)100% (4/4)
setHoldResultsOpenOverClose (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setMaxRows (int): void 100% (1/1)100% (50/50)100% (11/11)
setQueryTimeout (int): void 100% (1/1)100% (11/11)100% (4/4)
setResultSetConcurrency (int): void 100% (1/1)100% (4/4)100% (2/2)
setResultSetType (int): void 100% (1/1)100% (4/4)100% (2/2)
     
class Statement$CancelTask100% (1/1)100% (2/2)100% (23/23)100% (7/7)
Statement$CancelTask (Statement): void 100% (1/1)100% (15/15)100% (4/4)
run (): void 100% (1/1)100% (8/8)100% (3/3)

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

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