EMMA Coverage Report (generated Tue Jul 25 07:27:46 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [ServerPreparedStatement.java]

nameclass, %method, %block, %line, %
ServerPreparedStatement.java100% (3/3)83%  (60/72)77%  (3065/3965)77%  (754.5/986)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ServerPreparedStatement$BindValue100% (1/1)80%  (4/5)60%  (104/174)67%  (31/46)
toString (): String 0%   (0/1)0%   (0/4)0%   (0/1)
toString (boolean): String 100% (1/1)13%  (10/76)18%  (3/17)
ServerPreparedStatement$BindValue (): void 100% (1/1)100% (9/9)100% (4/4)
ServerPreparedStatement$BindValue (ServerPreparedStatement$BindValue): void 100% (1/1)100% (57/57)100% (16/16)
reset (): void 100% (1/1)100% (28/28)100% (10/10)
     
class ServerPreparedStatement100% (1/1)83%  (55/66)78%  (2934/3764)77%  (717.5/934)
getBytes (int): byte [] 0%   (0/1)0%   (0/64)0%   (0/15)
getParameterMetaData (): ParameterMetaData 0%   (0/1)0%   (0/17)0%   (0/4)
isNull (int): boolean 0%   (0/1)0%   (0/6)0%   (0/1)
rePrepare (): void 0%   (0/1)0%   (0/62)0%   (0/22)
setArray (int, Array): void 0%   (0/1)0%   (0/4)0%   (0/1)
setAsciiStream (int, InputStream, int): void 0%   (0/1)0%   (0/40)0%   (0/14)
setNull (int, int, String): void 0%   (0/1)0%   (0/24)0%   (0/8)
setRef (int, Ref): void 0%   (0/1)0%   (0/4)0%   (0/1)
setURL (int, URL): void 0%   (0/1)0%   (0/8)0%   (0/3)
setUnicodeStream (int, InputStream, int): void 0%   (0/1)0%   (0/6)0%   (0/2)
storeDataTime412AndOlder (Buffer, Date): void 0%   (0/1)0%   (0/94)0%   (0/24)
executeInternal (int, Buffer, boolean, boolean, boolean, boolean): ResultSet 100% (1/1)49%  (46/94)48%  (11/23)
serverLongData (int, ServerPreparedStatement$BindValue): void 100% (1/1)54%  (57/105)59%  (12.5/21)
asSql (boolean): String 100% (1/1)57%  (76/133)51%  (15.2/30)
checkClosed (): void 100% (1/1)67%  (6/9)75%  (3/4)
serverResetStatement (): void 100% (1/1)68%  (44/65)63%  (9.4/15)
storeReader (MysqlIO, int, Buffer, Reader): void 100% (1/1)68%  (129/190)67%  (33.4/50)
setBigDecimal (int, BigDecimal): void 100% (1/1)69%  (11/16)67%  (4/6)
toString (): String 100% (1/1)72%  (26/36)70%  (7/10)
storeStream (MysqlIO, int, Buffer, InputStream): void 100% (1/1)76%  (105/139)78%  (30.4/39)
setTimestampInternal (int, Timestamp, Calendar, TimeZone, boolean): void 100% (1/1)76%  (45/59)81%  (9.7/12)
storeDateTime (Buffer, Date, MysqlIO): void 100% (1/1)76%  (13/17)80%  (4/5)
storeBinding (Buffer, ServerPreparedStatement$BindValue, MysqlIO): void 100% (1/1)80%  (95/119)85%  (29/34)
setBlob (int, Blob): void 100% (1/1)80%  (32/40)79%  (11/14)
setCharacterStream (int, Reader, int): void 100% (1/1)80%  (32/40)79%  (11/14)
setTimeInternal (int, Time, Calendar, TimeZone, boolean): void 100% (1/1)80%  (41/51)82%  (9.9/12)
setBytes (int, byte []): void 100% (1/1)82%  (23/28)80%  (8/10)
storeTime (Buffer, Time): void 100% (1/1)82%  (51/62)94%  (14.1/15)
setString (int, String): void 100% (1/1)83%  (24/29)80%  (8/10)
getBinding (int, boolean): ServerPreparedStatement$BindValue 100% (1/1)84%  (70/83)79%  (11/14)
ServerPreparedStatement (Connection, String, String): void 100% (1/1)86%  (103/120)85%  (24.7/29)
storeDateTime413AndNewer (Buffer, Date): void 100% (1/1)89%  (121/136)94%  (31/33)
executeBatch (): int [] 100% (1/1)92%  (235/255)95%  (55/58)
setBinaryStream (int, InputStream, int): void 100% (1/1)92%  (37/40)93%  (13/14)
setClob (int, Clob): void 100% (1/1)93%  (38/41)93%  (13/14)
dumpExecuteForTestcase (): void 100% (1/1)93%  (115/124)89%  (25/28)
realClose (boolean, boolean): void 100% (1/1)94%  (73/78)88%  (22/25)
serverExecute (int, boolean): ResultSet 100% (1/1)94%  (520/553)95%  (96.2/101)
serverPrepare (String): void 100% (1/1)97%  (268/275)95%  (55/58)
addBatch (): void 100% (1/1)100% (20/20)100% (5/5)
clearParameters (): void 100% (1/1)100% (6/6)100% (3/3)
clearParametersInternal (boolean): void 100% (1/1)100% (41/41)100% (10/10)
close (): void 100% (1/1)100% (16/16)100% (6/6)
dumpCloseForTestcase (): void 100% (1/1)100% (28/28)100% (7/7)
dumpPrepareForTestcase (): void 100% (1/1)100% (42/42)100% (9/9)
fillSendPacket (): Buffer 100% (1/1)100% (2/2)100% (1/1)
fillSendPacket (byte [][], InputStream [], boolean [], int []): Buffer 100% (1/1)100% (2/2)100% (1/1)
getMetaData (): ResultSetMetaData 100% (1/1)100% (13/13)100% (4/4)
getServerStatementId (): long 100% (1/1)100% (3/3)100% (1/1)
setBoolean (int, boolean): void 100% (1/1)100% (9/9)100% (2/2)
setByte (int, byte): void 100% (1/1)100% (24/24)100% (8/8)
setClosed (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setDate (int, Date): void 100% (1/1)100% (6/6)100% (2/2)
setDate (int, Date, Calendar): void 100% (1/1)100% (26/26)100% (9/9)
setDouble (int, double): void 100% (1/1)100% (52/52)100% (10/10)
setFloat (int, float): void 100% (1/1)100% (24/24)100% (8/8)
setInt (int, int): void 100% (1/1)100% (24/24)100% (8/8)
setLong (int, long): void 100% (1/1)100% (24/24)100% (8/8)
setNull (int, int): void 100% (1/1)100% (24/24)100% (8/8)
setShort (int, short): void 100% (1/1)100% (24/24)100% (8/8)
setTime (int, Time): void 100% (1/1)100% (8/8)100% (2/2)
setTime (int, Time, Calendar): void 100% (1/1)100% (9/9)100% (2/2)
setTimestamp (int, Timestamp): void 100% (1/1)100% (8/8)100% (2/2)
setTimestamp (int, Timestamp, Calendar): void 100% (1/1)100% (9/9)100% (2/2)
setType (ServerPreparedStatement$BindValue, int): void 100% (1/1)100% (11/11)100% (4/4)
truncateQueryToLog (String): String 100% (1/1)100% (39/39)100% (9/9)
     
class ServerPreparedStatement$BatchedBindValues100% (1/1)100% (1/1)100% (27/27)100% (6/6)
ServerPreparedStatement$BatchedBindValues (ServerPreparedStatement$BindValue ... 100% (1/1)100% (27/27)100% (6/6)

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.Statement.CancelTask;
28import com.mysql.jdbc.exceptions.MySQLTimeoutException;
29import com.mysql.jdbc.profiler.ProfileEventSink;
30import com.mysql.jdbc.profiler.ProfilerEvent;
31 
32import java.io.ByteArrayInputStream;
33import java.io.IOException;
34import java.io.InputStream;
35import java.io.Reader;
36import java.io.UnsupportedEncodingException;
37 
38import java.math.BigDecimal;
39 
40import java.net.URL;
41 
42import java.sql.Array;
43import java.sql.Blob;
44import java.sql.Clob;
45import java.sql.Date;
46import java.sql.ParameterMetaData;
47import java.sql.Ref;
48import java.sql.SQLException;
49import java.sql.Time;
50import java.sql.Timestamp;
51import java.sql.Types;
52 
53import java.util.ArrayList;
54import java.util.BitSet;
55import java.util.Calendar;
56import java.util.Locale;
57import java.util.TimeZone;
58 
59/**
60 * JDBC Interface for MySQL-4.1 and newer server-side PreparedStatements.
61 * 
62 * @author Mark Matthews
63 * @version $Id: ServerPreparedStatement.java,v 1.1.2.2 2005/05/17 14:58:56
64 *          mmatthews Exp $
65 */
66public class ServerPreparedStatement extends PreparedStatement {
67        protected static final int BLOB_STREAM_READ_BUF_SIZE = 8192;
68 
69        static class BatchedBindValues {
70                BindValue[] batchedParameterValues;
71 
72                BatchedBindValues(BindValue[] paramVals) {
73                        int numParams = paramVals.length;
74 
75                        this.batchedParameterValues = new BindValue[numParams];
76 
77                        for (int i = 0; i < numParams; i++) {
78                                this.batchedParameterValues[i] = new BindValue(paramVals[i]);
79                        }
80                }
81        }
82 
83        static class BindValue {
84 
85                long boundBeforeExecutionNum = 0;
86                
87                long bindLength; /* Default length of data */
88 
89                int bufferType; /* buffer type */
90 
91                byte byteBinding;
92 
93                double doubleBinding;
94 
95                float floatBinding;
96 
97                int intBinding;
98 
99                boolean isLongData; /* long data indicator */
100 
101                boolean isNull; /* NULL indicator */
102 
103                boolean isSet = false; /* has this parameter been set? */
104 
105                long longBinding;
106 
107                short shortBinding;
108 
109                Object value; /* The value to store */
110 
111                BindValue() {
112                }
113 
114                BindValue(BindValue copyMe) {
115                        this.value = copyMe.value;
116                        this.isSet = copyMe.isSet;
117                        this.isLongData = copyMe.isLongData;
118                        this.isNull = copyMe.isNull;
119                        this.bufferType = copyMe.bufferType;
120                        this.bindLength = copyMe.bindLength;
121                        this.byteBinding = copyMe.byteBinding;
122                        this.shortBinding = copyMe.shortBinding;
123                        this.intBinding = copyMe.intBinding;
124                        this.longBinding = copyMe.longBinding;
125                        this.floatBinding = copyMe.floatBinding;
126                        this.doubleBinding = copyMe.doubleBinding;
127                }
128 
129                void reset() {
130                        this.isSet = false;
131                        this.value = null;
132                        this.isLongData = false;
133 
134                        this.byteBinding = 0;
135                        this.shortBinding = 0;
136                        this.intBinding = 0;
137                        this.longBinding = 0L;
138                        this.floatBinding = 0;
139                        this.doubleBinding = 0D;
140                }
141 
142                public String toString() {
143                        return toString(false);
144                }
145 
146                public String toString(boolean quoteIfNeeded) {
147                        if (this.isLongData) {
148                                return "' STREAM DATA '";
149                        }
150 
151                        switch (this.bufferType) {
152                        case MysqlDefs.FIELD_TYPE_TINY:
153                                return String.valueOf(byteBinding);
154                        case MysqlDefs.FIELD_TYPE_SHORT:
155                                return String.valueOf(shortBinding);
156                        case MysqlDefs.FIELD_TYPE_LONG:
157                                return String.valueOf(intBinding);
158                        case MysqlDefs.FIELD_TYPE_LONGLONG:
159                                return String.valueOf(longBinding);
160                        case MysqlDefs.FIELD_TYPE_FLOAT:
161                                return String.valueOf(floatBinding);
162                        case MysqlDefs.FIELD_TYPE_DOUBLE:
163                                return String.valueOf(doubleBinding);
164                        case MysqlDefs.FIELD_TYPE_TIME:
165                        case MysqlDefs.FIELD_TYPE_DATE:
166                        case MysqlDefs.FIELD_TYPE_DATETIME:
167                        case MysqlDefs.FIELD_TYPE_TIMESTAMP:
168                        case MysqlDefs.FIELD_TYPE_VAR_STRING:
169                        case MysqlDefs.FIELD_TYPE_STRING:
170                        case MysqlDefs.FIELD_TYPE_VARCHAR:
171                                if (quoteIfNeeded) {
172                                        return "'" + String.valueOf(value) + "'";
173                                } else {
174                                        return String.valueOf(value);
175                                }
176                        default:
177                                if (value instanceof byte[]) {
178                                        return "byte data";
179 
180                                } else {
181                                        if (quoteIfNeeded) {
182                                                return "'" + String.valueOf(value) + "'";
183                                        } else {
184                                                return String.valueOf(value);
185                                        }
186                                }
187                        }
188                }
189        }
190 
191        /* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
192        private static final byte MAX_DATE_REP_LENGTH = (byte) 5;
193 
194        /*
195         * 1 (length) + 2 (year) + 1 (month) + 1 (day) + 1 (hour) + 1 (minute) + 1
196         * (second) + 4 (microseconds)
197         */
198        private static final byte MAX_DATETIME_REP_LENGTH = 12;
199 
200        /*
201         * 1 (length) + 1 (is negative) + 4 (day count) + 1 (hour) + 1 (minute) + 1
202         * (seconds) + 4 (microseconds)
203         */
204        private static final byte MAX_TIME_REP_LENGTH = 13;
205 
206        private void storeTime(Buffer intoBuf, Time tm) throws SQLException {
207                
208                intoBuf.ensureCapacity(9);
209                intoBuf.writeByte((byte) 8); // length
210                intoBuf.writeByte((byte) 0); // neg flag
211                intoBuf.writeLong(0); // tm->day, not used
212 
213                Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
214                
215                synchronized (sessionCalendar) {
216                        java.util.Date oldTime = sessionCalendar.getTime();
217                        try {
218                                sessionCalendar.setTime(tm);
219                                intoBuf.writeByte((byte) sessionCalendar.get(Calendar.HOUR_OF_DAY));
220                                intoBuf.writeByte((byte) sessionCalendar.get(Calendar.MINUTE));
221                                intoBuf.writeByte((byte) sessionCalendar.get(Calendar.SECOND));
222 
223                                // intoBuf.writeLongInt(0); // tm-second_part
224                        } finally {
225                                sessionCalendar.setTime(oldTime);
226                        }
227                }
228        }
229 
230        /**
231         * Flag indicating whether or not the long parameters have been 'switched'
232         * back to normal parameters. We can not execute() if clearParameters()
233         * hasn't been called in this case.
234         */
235        private boolean detectedLongParameterSwitch = false;
236 
237        /**
238         * The number of fields in the result set (if any) for this
239         * PreparedStatement.
240         */
241        private int fieldCount;
242 
243        /** Has this prepared statement been marked invalid? */
244        private boolean invalid = false;
245 
246        /** If this statement has been marked invalid, what was the reason? */
247        private SQLException invalidationException;
248 
249        /** Does this query modify data? */
250        private boolean isSelectQuery;
251 
252        private Buffer outByteBuffer;
253 
254        /** Bind values for individual fields */
255        private BindValue[] parameterBindings;
256 
257        /** Field-level metadata for parameters */
258        private Field[] parameterFields;
259 
260        /** Field-level metadata for result sets. */
261        private Field[] resultFields;
262 
263        /** Do we need to send/resend types to the server? */
264        private boolean sendTypesToServer = false;
265 
266        /** The ID that the server uses to identify this PreparedStatement */
267        private long serverStatementId;
268 
269        /** The type used for string bindings, changes from version-to-version */
270        private int stringTypeCode = MysqlDefs.FIELD_TYPE_STRING;
271 
272        private boolean serverNeedsResetBeforeEachExecution;
273 
274        /**
275         * Creates a new ServerPreparedStatement object.
276         * 
277         * @param conn
278         *            the connection creating us.
279         * @param sql
280         *            the SQL containing the statement to prepare.
281         * @param catalog
282         *            the catalog in use when we were created.
283         * 
284         * @throws SQLException
285         *             If an error occurs
286         */
287        public ServerPreparedStatement(Connection conn, String sql, String catalog)
288                        throws SQLException {
289                super(conn, catalog);
290 
291                checkNullOrEmptyQuery(sql);
292 
293                this.isSelectQuery = StringUtils.startsWithIgnoreCaseAndWs(sql,
294                                "SELECT"); //$NON-NLS-1$
295                
296                if (this.connection.versionMeetsMinimum(5, 0, 0)) {
297                        this.serverNeedsResetBeforeEachExecution = 
298                                !this.connection.versionMeetsMinimum(5, 0, 3);
299                } else {
300                        this.serverNeedsResetBeforeEachExecution =
301                                !this.connection.versionMeetsMinimum(4, 1, 10);
302                }
303                
304                this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
305                this.hasLimitClause = (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1); //$NON-NLS-1$
306                this.firstCharOfStmt = StringUtils.firstNonWsCharUc(sql);
307                this.originalSql = sql;
308 
309                if (this.connection.versionMeetsMinimum(4, 1, 2)) {
310                        this.stringTypeCode = MysqlDefs.FIELD_TYPE_VAR_STRING;
311                } else {
312                        this.stringTypeCode = MysqlDefs.FIELD_TYPE_STRING;
313                }
314 
315                try {
316                        serverPrepare(sql);
317                } catch (SQLException sqlEx) {
318                        realClose(false, true);
319                        // don't wrap SQLExceptions
320                        throw sqlEx;
321                } catch (Exception ex) {
322                        realClose(false, true);
323 
324                        throw SQLError.createSQLException(ex.toString(),
325                                        SQLError.SQL_STATE_GENERAL_ERROR);
326                }
327        }
328 
329        /**
330         * JDBC 2.0 Add a set of parameters to the batch.
331         * 
332         * @exception SQLException
333         *                if a database-access error occurs.
334         * 
335         * @see Statement#addBatch
336         */
337        public synchronized void addBatch() throws SQLException {
338                checkClosed();
339 
340                if (this.batchedArgs == null) {
341                        this.batchedArgs = new ArrayList();
342                }
343 
344                this.batchedArgs.add(new BatchedBindValues(this.parameterBindings));
345        }
346 
347        protected String asSql(boolean quoteStreamsAndUnknowns) throws SQLException {
348 
349                PreparedStatement pStmtForSub = null;
350 
351                try {
352                        pStmtForSub = new PreparedStatement(this.connection,
353                                        this.originalSql, this.currentCatalog);
354 
355                        int numParameters = pStmtForSub.parameterCount;
356                        int ourNumParameters = this.parameterCount;
357 
358                        for (int i = 0; (i < numParameters) && (i < ourNumParameters); i++) {
359                                if (this.parameterBindings[i] != null) {
360                                        if (this.parameterBindings[i].isNull) {
361                                                pStmtForSub.setNull(i + 1, Types.NULL);
362                                        } else {
363                                                BindValue bindValue = this.parameterBindings[i];
364 
365                                                //
366                                                // Handle primitives first
367                                                //
368                                                switch (bindValue.bufferType) {
369 
370                                                case MysqlDefs.FIELD_TYPE_TINY:
371                                                        pStmtForSub.setByte(i + 1, bindValue.byteBinding);
372                                                        break;
373                                                case MysqlDefs.FIELD_TYPE_SHORT:
374                                                        pStmtForSub.setShort(i + 1, bindValue.shortBinding);
375                                                        break;
376                                                case MysqlDefs.FIELD_TYPE_LONG:
377                                                        pStmtForSub.setInt(i + 1, bindValue.intBinding);
378                                                        break;
379                                                case MysqlDefs.FIELD_TYPE_LONGLONG:
380                                                        pStmtForSub.setLong(i + 1, bindValue.longBinding);
381                                                        break;
382                                                case MysqlDefs.FIELD_TYPE_FLOAT:
383                                                        pStmtForSub.setFloat(i + 1, bindValue.floatBinding);
384                                                        break;
385                                                case MysqlDefs.FIELD_TYPE_DOUBLE:
386                                                        pStmtForSub.setDouble(i + 1,
387                                                                        bindValue.doubleBinding);
388                                                        break;
389                                                default:
390                                                        pStmtForSub.setObject(i + 1,
391                                                                        this.parameterBindings[i].value);
392                                                        break;
393                                                }
394                                        }
395                                }
396                        }
397 
398                        return pStmtForSub.asSql(quoteStreamsAndUnknowns);
399                } finally {
400                        if (pStmtForSub != null) {
401                                try {
402                                        pStmtForSub.close();
403                                } catch (SQLException sqlEx) {
404                                        ; // ignore
405                                }
406                        }
407                }
408        }
409 
410        /*
411         * (non-Javadoc)
412         * 
413         * @see com.mysql.jdbc.Statement#checkClosed()
414         */
415        protected void checkClosed() throws SQLException {
416                if (this.invalid) {
417                        throw this.invalidationException;
418                }
419 
420                super.checkClosed();
421        }
422 
423        /**
424         * @see java.sql.PreparedStatement#clearParameters()
425         */
426        public void clearParameters() throws SQLException {
427                checkClosed();
428                clearParametersInternal(true);
429        }
430 
431        private void clearParametersInternal(boolean clearServerParameters)
432                        throws SQLException {
433                boolean hadLongData = false;
434 
435                if (this.parameterBindings != null) {
436                        for (int i = 0; i < this.parameterCount; i++) {
437                                if ((this.parameterBindings[i] != null)
438                                                && this.parameterBindings[i].isLongData) {
439                                        hadLongData = true;
440                                }
441 
442                                this.parameterBindings[i].reset();
443                        }
444                }
445 
446                if (clearServerParameters && hadLongData) {
447                        serverResetStatement();
448 
449                        this.detectedLongParameterSwitch = false;
450                }
451        }
452 
453        protected boolean isCached = false;
454 
455        protected void setClosed(boolean flag) {
456                this.isClosed = flag;
457        }
458        /**
459         * @see java.sql.Statement#close()
460         */
461        public void close() throws SQLException {
462                if (this.isCached) {
463                        this.isClosed = true;
464                        this.connection.recachePreparedStatement(this);
465                        return;
466                }
467                
468                realClose(true, true);
469        }
470 
471        private void dumpCloseForTestcase() {
472                StringBuffer buf = new StringBuffer();
473                this.connection.generateConnectionCommentBlock(buf);
474                buf.append("DEALLOCATE PREPARE debug_stmt_");
475                buf.append(this.statementId);
476                buf.append(";\n");
477 
478                this.connection.dumpTestcaseQuery(buf.toString());
479        }
480 
481        private void dumpExecuteForTestcase() throws SQLException {
482                StringBuffer buf = new StringBuffer();
483 
484                for (int i = 0; i < this.parameterCount; i++) {
485                        this.connection.generateConnectionCommentBlock(buf);
486 
487                        buf.append("SET @debug_stmt_param");
488                        buf.append(this.statementId);
489                        buf.append("_");
490                        buf.append(i);
491                        buf.append("=");
492 
493                        if (this.parameterBindings[i].isNull) {
494                                buf.append("NULL");
495                        } else {
496                                buf.append(this.parameterBindings[i].toString(true));
497                        }
498 
499                        buf.append(";\n");
500                }
501 
502                this.connection.generateConnectionCommentBlock(buf);
503 
504                buf.append("EXECUTE debug_stmt_");
505                buf.append(this.statementId);
506 
507                if (this.parameterCount > 0) {
508                        buf.append(" USING ");
509                        for (int i = 0; i < this.parameterCount; i++) {
510                                if (i > 0) {
511                                        buf.append(", ");
512                                }
513 
514                                buf.append("@debug_stmt_param");
515                                buf.append(this.statementId);
516                                buf.append("_");
517                                buf.append(i);
518 
519                        }
520                }
521 
522                buf.append(";\n");
523 
524                this.connection.dumpTestcaseQuery(buf.toString());
525        }
526 
527        private void dumpPrepareForTestcase() throws SQLException {
528 
529                StringBuffer buf = new StringBuffer(this.originalSql.length() + 64);
530 
531                this.connection.generateConnectionCommentBlock(buf);
532 
533                buf.append("PREPARE debug_stmt_");
534                buf.append(this.statementId);
535                buf.append(" FROM \"");
536                buf.append(this.originalSql);
537                buf.append("\";\n");
538 
539                this.connection.dumpTestcaseQuery(buf.toString());
540        }
541 
542        /**
543         * @see java.sql.Statement#executeBatch()
544         */
545        public synchronized int[] executeBatch() throws SQLException {
546                if (this.connection.isReadOnly()) {
547                        throw SQLError.createSQLException(Messages
548                                        .getString("ServerPreparedStatement.2") //$NON-NLS-1$
549                                        + Messages.getString("ServerPreparedStatement.3"), //$NON-NLS-1$
550                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
551                }
552 
553                checkClosed();
554 
555                synchronized (this.connection.getMutex()) {
556                        clearWarnings();
557 
558                        // Store this for later, we're going to 'swap' them out
559                        // as we execute each batched statement...
560                        BindValue[] oldBindValues = this.parameterBindings;
561 
562                        try {
563                                int[] updateCounts = null;
564 
565                                if (this.batchedArgs != null) {
566                                        int nbrCommands = this.batchedArgs.size();
567                                        updateCounts = new int[nbrCommands];
568 
569                                        if (this.retrieveGeneratedKeys) {
570                                                this.batchedGeneratedKeys = new ArrayList(nbrCommands);
571                                        }
572 
573                                        for (int i = 0; i < nbrCommands; i++) {
574                                                updateCounts[i] = -3;
575                                        }
576 
577                                        SQLException sqlEx = null;
578 
579                                        int commandIndex = 0;
580 
581                                        BindValue[] previousBindValuesForBatch = null;
582 
583                                        for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
584                                                Object arg = this.batchedArgs.get(commandIndex);
585 
586                                                if (arg instanceof String) {
587                                                        updateCounts[commandIndex] = executeUpdate((String) arg);
588                                                } else {
589                                                        this.parameterBindings = ((BatchedBindValues) arg).batchedParameterValues;
590 
591                                                        try {
592                                                                // We need to check types each time, as
593                                                                // the user might have bound different
594                                                                // types in each addBatch()
595 
596                                                                if (previousBindValuesForBatch != null) {
597                                                                        for (int j = 0; j < this.parameterBindings.length; j++) {
598                                                                                if (this.parameterBindings[j].bufferType != previousBindValuesForBatch[j].bufferType) {
599                                                                                        this.sendTypesToServer = true;
600 
601                                                                                        break;
602                                                                                }
603                                                                        }
604                                                                }
605 
606                                                                try {
607                                                                        updateCounts[commandIndex] = executeUpdate(false, true);
608                                                                } finally {
609                                                                        previousBindValuesForBatch = this.parameterBindings;
610                                                                }
611 
612                                                                if (this.retrieveGeneratedKeys) {
613                                                                        java.sql.ResultSet rs = null;
614 
615                                                                        try {
616                                                                                // we don't want to use our version,
617                                                                                // because we've altered the behavior of
618                                                                                // ours to support batch updates
619                                                                                // (catch-22)
620                                                                                // Ideally, what we need here is
621                                                                                // super.super.getGeneratedKeys()
622                                                                                // but that construct doesn't exist in
623                                                                                // Java, so that's why there's
624                                                                                // this kludge.
625                                                                                rs = getGeneratedKeysInternal();
626 
627                                                                                while (rs.next()) {
628                                                                                        this.batchedGeneratedKeys
629                                                                                                        .add(new byte[][] { rs
630                                                                                                                        .getBytes(1) });
631                                                                                }
632                                                                        } finally {
633                                                                                if (rs != null) {
634                                                                                        rs.close();
635                                                                                }
636                                                                        }
637                                                                }
638                                                        } catch (SQLException ex) {
639                                                                updateCounts[commandIndex] = EXECUTE_FAILED;
640 
641                                                                if (this.connection.getContinueBatchOnError()) {
642                                                                        sqlEx = ex;
643                                                                } else {
644                                                                        int[] newUpdateCounts = new int[commandIndex];
645                                                                        System.arraycopy(updateCounts, 0,
646                                                                                        newUpdateCounts, 0, commandIndex);
647 
648                                                                        throw new java.sql.BatchUpdateException(ex
649                                                                                        .getMessage(), ex.getSQLState(), ex
650                                                                                        .getErrorCode(), newUpdateCounts);
651                                                                }
652                                                        }
653                                                }
654                                        }
655 
656                                        if (sqlEx != null) {
657                                                throw new java.sql.BatchUpdateException(sqlEx
658                                                                .getMessage(), sqlEx.getSQLState(), sqlEx
659                                                                .getErrorCode(), updateCounts);
660                                        }
661                                }
662 
663                                return (updateCounts != null) ? updateCounts : new int[0];
664                        } finally {
665                                this.parameterBindings = oldBindValues;
666                                this.sendTypesToServer = true;
667 
668                                clearBatch();
669                        }
670                }
671        }
672 
673        /**
674         * @see com.mysql.jdbc.PreparedStatement#executeInternal(int,
675         *      com.mysql.jdbc.Buffer, boolean, boolean)
676         */
677        protected com.mysql.jdbc.ResultSet executeInternal(int maxRowsToRetrieve,
678                        Buffer sendPacket, boolean createStreamingResultSet,
679                        boolean queryIsSelectOnly, boolean unpackFields, boolean isBatch)
680                        throws SQLException {
681                this.numberOfExecutions++;
682 
683                // We defer to server-side execution
684                try {
685                        return serverExecute(maxRowsToRetrieve, createStreamingResultSet);
686                } catch (SQLException sqlEx) {
687                        // don't wrap SQLExceptions
688                        if (this.connection.getEnablePacketDebug()) {
689                                this.connection.getIO().dumpPacketRingBuffer();
690                        }
691 
692                        if (this.connection.getDumpQueriesOnException()) {
693                                String extractedSql = toString();
694                                StringBuffer messageBuf = new StringBuffer(extractedSql
695                                                .length() + 32);
696                                messageBuf
697                                                .append("\n\nQuery being executed when exception was thrown:\n\n");
698                                messageBuf.append(extractedSql);
699 
700                                sqlEx = Connection.appendMessageToException(sqlEx, messageBuf
701                                                .toString());
702                        }
703 
704                        throw sqlEx;
705                } catch (Exception ex) {
706                        if (this.connection.getEnablePacketDebug()) {
707                                this.connection.getIO().dumpPacketRingBuffer();
708                        }
709 
710                        SQLException sqlEx = SQLError.createSQLException(ex.toString(),
711                                        SQLError.SQL_STATE_GENERAL_ERROR);
712 
713                        if (this.connection.getDumpQueriesOnException()) {
714                                String extractedSql = toString();
715                                StringBuffer messageBuf = new StringBuffer(extractedSql
716                                                .length() + 32);
717                                messageBuf
718                                                .append("\n\nQuery being executed when exception was thrown:\n\n");
719                                messageBuf.append(extractedSql);
720 
721                                sqlEx = Connection.appendMessageToException(sqlEx, messageBuf
722                                                .toString());
723                        }
724 
725                        throw sqlEx;
726                }
727        }
728 
729        /**
730         * @see com.mysql.jdbc.PreparedStatement#fillSendPacket()
731         */
732        protected Buffer fillSendPacket() throws SQLException {
733                return null; // we don't use this type of packet
734        }
735 
736        /**
737         * @see com.mysql.jdbc.PreparedStatement#fillSendPacket(byte,
738         *      java.io.InputStream, boolean, int)
739         */
740        protected Buffer fillSendPacket(byte[][] batchedParameterStrings,
741                        InputStream[] batchedParameterStreams, boolean[] batchedIsStream,
742                        int[] batchedStreamLengths) throws SQLException {
743                return null; // we don't use this type of packet
744        }
745 
746        private BindValue getBinding(int parameterIndex, boolean forLongData)
747                        throws SQLException {
748                checkClosed();
749                
750                if (this.parameterBindings.length == 0) {
751                        throw SQLError.createSQLException(Messages
752                                        .getString("ServerPreparedStatement.8"), //$NON-NLS-1$
753                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
754                }
755 
756                parameterIndex--;
757 
758                if ((parameterIndex < 0)
759                                || (parameterIndex >= this.parameterBindings.length)) {
760                        throw SQLError.createSQLException(Messages
761                                        .getString("ServerPreparedStatement.9") //$NON-NLS-1$
762                                        + (parameterIndex + 1)
763                                        + Messages.getString("ServerPreparedStatement.10") //$NON-NLS-1$
764                                        + this.parameterBindings.length,
765                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
766                }
767 
768                if (this.parameterBindings[parameterIndex] == null) {
769                        this.parameterBindings[parameterIndex] = new BindValue();
770                } else {
771                        if (this.parameterBindings[parameterIndex].isLongData
772                                        && !forLongData) {
773                                this.detectedLongParameterSwitch = true;
774                        }
775                }
776 
777                this.parameterBindings[parameterIndex].isSet = true;
778                this.parameterBindings[parameterIndex].boundBeforeExecutionNum = this.numberOfExecutions;
779 
780                return this.parameterBindings[parameterIndex];
781        }
782 
783        /**
784         * @see com.mysql.jdbc.PreparedStatement#getBytes(int)
785         */
786        byte[] getBytes(int parameterIndex) throws SQLException {
787                BindValue bindValue = getBinding(parameterIndex, false);
788 
789                if (bindValue.isNull) {
790                        return null;
791                } else if (bindValue.isLongData) {
792                        throw new NotImplemented();
793                } else {
794                        if (this.outByteBuffer == null) {
795                                this.outByteBuffer = new Buffer(this.connection
796                                                .getNetBufferLength());
797                        }
798 
799                        this.outByteBuffer.clear();
800 
801                        int originalPosition = this.outByteBuffer.getPosition();
802 
803                        storeBinding(this.outByteBuffer, bindValue, this.connection.getIO());
804 
805                        int newPosition = this.outByteBuffer.getPosition();
806 
807                        int length = newPosition - originalPosition;
808 
809                        byte[] valueAsBytes = new byte[length];
810 
811                        System.arraycopy(this.outByteBuffer.getByteBuffer(),
812                                        originalPosition, valueAsBytes, 0, length);
813 
814                        return valueAsBytes;
815                }
816        }
817 
818        /**
819         * @see java.sql.PreparedStatement#getMetaData()
820         */
821        public java.sql.ResultSetMetaData getMetaData() throws SQLException {
822                checkClosed();
823 
824                if (this.resultFields == null) {
825                        return null;
826                }
827 
828                return new ResultSetMetaData(this.resultFields);
829        }
830 
831        /**
832         * @see java.sql.PreparedStatement#getParameterMetaData()
833         */
834        public ParameterMetaData getParameterMetaData() throws SQLException {
835                checkClosed();
836                
837                if (this.parameterMetaData == null) {
838                        this.parameterMetaData = new MysqlParameterMetadata(
839                                        this.parameterFields, this.parameterCount);
840                }
841                
842                return this.parameterMetaData;
843        }
844 
845        /**
846         * @see com.mysql.jdbc.PreparedStatement#isNull(int)
847         */
848        boolean isNull(int paramIndex) {
849                throw new IllegalArgumentException(Messages
850                                .getString("ServerPreparedStatement.7")); //$NON-NLS-1$
851        }
852 
853        /**
854         * Closes this connection and frees all resources.
855         * 
856         * @param calledExplicitly
857         *            was this called from close()?
858         * 
859         * @throws SQLException
860         *             if an error occurs
861         */
862        protected void realClose(boolean calledExplicitly, 
863                        boolean closeOpenResults) throws SQLException {
864                if (this.isClosed) {
865                        return;
866                }
867 
868                if (this.connection != null) {
869                        if (this.connection.getAutoGenerateTestcaseScript()) {
870                                dumpCloseForTestcase();
871                        }
872                        
873                        synchronized (this.connection.getMutex()) {
874        
875                                //
876                                // Don't communicate with the server if we're being
877                                // called from the finalizer...
878                                // 
879                                // This will leak server resources, but if we don't do this,
880                                // we'll deadlock (potentially, because there's no guarantee
881                                // when, what order, and what concurrency finalizers will be
882                                // called with). Well-behaved programs won't rely on finalizers
883                                // to clean up their statements.
884                                //
885                                
886                                SQLException exceptionDuringClose = null;
887                                
888 
889                                if (calledExplicitly) {
890                                        try {
891                                                
892                                                MysqlIO mysql = this.connection.getIO();
893                                                
894                                                Buffer packet = mysql.getSharedSendPacket();
895                                                
896                                                packet.writeByte((byte) MysqlDefs.COM_CLOSE_STATEMENT);
897                                                packet.writeLong(this.serverStatementId);
898                                                
899                                                mysql.sendCommand(MysqlDefs.COM_CLOSE_STATEMENT, null,
900                                                                packet, true, null);
901                                        } catch (SQLException sqlEx) {
902                                                exceptionDuringClose = sqlEx;
903                                        }
904                                        
905                                }
906 
907                                super.realClose(calledExplicitly, closeOpenResults);
908 
909                                clearParametersInternal(false);
910                                this.parameterBindings = null;
911                                
912                                this.parameterFields = null;
913                                this.resultFields = null;
914                                
915                                if (exceptionDuringClose != null) {
916                                        throw exceptionDuringClose;
917                                }
918                        }
919                }
920        }
921 
922        /**
923         * Used by Connection when auto-reconnecting to retrieve 'lost' prepared
924         * statements.
925         * 
926         * @throws SQLException
927         *             if an error occurs.
928         */
929        protected void rePrepare() throws SQLException {
930                this.invalidationException = null;
931 
932                try {
933                        serverPrepare(this.originalSql);
934                } catch (SQLException sqlEx) {
935                        // don't wrap SQLExceptions
936                        this.invalidationException = sqlEx;
937                } catch (Exception ex) {
938                        this.invalidationException = SQLError.createSQLException(ex.toString(),
939                                        SQLError.SQL_STATE_GENERAL_ERROR);
940                }
941 
942                if (this.invalidationException != null) {
943                        this.invalid = true;
944 
945                        this.parameterBindings = null;
946 
947                        this.parameterFields = null;
948                        this.resultFields = null;
949 
950                        if (this.results != null) {
951                                try {
952                                        this.results.close();
953                                } catch (Exception ex) {
954                                        ;
955                                }
956                        }
957 
958                        if (this.connection != null) {
959                                if (this.maxRowsChanged) {
960                                        this.connection.unsetMaxRows(this);
961                                }
962 
963                                if (!this.connection.getDontTrackOpenResources()) {
964                                        this.connection.unregisterStatement(this);
965                                }
966                        }
967                }
968        }
969 
970        /**
971         * Tells the server to execute this prepared statement with the current
972         * parameter bindings.
973         * 
974         * <pre>
975         * 
976         * 
977         *    -   Server gets the command 'COM_EXECUTE' to execute the
978         *        previously         prepared query. If there is any param markers;
979         *  then client will send the data in the following format:
980         * 
981         *  [COM_EXECUTE:1]
982         *  [STMT_ID:4]
983         *  [NULL_BITS:(param_count+7)/8)]
984         *  [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
985         *  [[length]data]
986         *  [[length]data] .. [[length]data].
987         * 
988         *  (Note: Except for string/binary types; all other types will not be
989         *  supplied with length field)
990         * 
991         *  
992         * </pre>
993         * 
994         * @param maxRowsToRetrieve
995         *            DOCUMENT ME!
996         * @param createStreamingResultSet
997         *            DOCUMENT ME!
998         * 
999         * @return DOCUMENT ME!
1000         * 
1001         * @throws SQLException
1002         */
1003        private com.mysql.jdbc.ResultSet serverExecute(int maxRowsToRetrieve,
1004                        boolean createStreamingResultSet) throws SQLException {
1005                synchronized (this.connection.getMutex()) {
1006                        if (this.detectedLongParameterSwitch) {
1007                                // Check when values were bound
1008                                boolean firstFound = false;
1009                                long boundTimeToCheck = 0;
1010                                
1011                                for (int i = 0; i < this.parameterCount - 1; i++) {
1012                                        if (this.parameterBindings[i].isLongData) {
1013                                                if (firstFound && boundTimeToCheck != 
1014                                                        this.parameterBindings[i].boundBeforeExecutionNum) {                                         
1015                                                        throw SQLError.createSQLException(Messages
1016                                                                        .getString("ServerPreparedStatement.11") //$NON-NLS-1$
1017                                                                        + Messages.getString("ServerPreparedStatement.12"), //$NON-NLS-1$
1018                                                                        SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
1019                                                } else {
1020                                                        firstFound = true;
1021                                                        boundTimeToCheck = this.parameterBindings[i].boundBeforeExecutionNum;
1022                                                }
1023                                        }
1024                                }
1025                                
1026                                // Okay, we've got all "newly"-bound streams, so reset 
1027                                // server-side state to clear out previous bindings
1028                                
1029                                serverResetStatement();
1030                        }
1031 
1032 
1033                        // Check bindings
1034                        for (int i = 0; i < this.parameterCount; i++) {
1035                                if (!this.parameterBindings[i].isSet) {
1036                                        throw SQLError.createSQLException(Messages
1037                                                        .getString("ServerPreparedStatement.13") + (i + 1) //$NON-NLS-1$
1038                                                        + Messages.getString("ServerPreparedStatement.14"),
1039                                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
1040                                }
1041                        }
1042 
1043                        //
1044                        // Send all long data
1045                        //
1046                        for (int i = 0; i < this.parameterCount; i++) {
1047                                if (this.parameterBindings[i].isLongData) {
1048                                        serverLongData(i, this.parameterBindings[i]);
1049                                }
1050                        }
1051 
1052                        if (this.connection.getAutoGenerateTestcaseScript()) {
1053                                dumpExecuteForTestcase();
1054                        }
1055 
1056                        //
1057                        // store the parameter values
1058                        //
1059                        MysqlIO mysql = this.connection.getIO();
1060 
1061                        Buffer packet = mysql.getSharedSendPacket();
1062 
1063                        packet.clear();
1064                        packet.writeByte((byte) MysqlDefs.COM_EXECUTE);
1065                        packet.writeLong(this.serverStatementId);
1066 
1067                        boolean usingCursor = false;
1068 
1069                        if (this.connection.versionMeetsMinimum(4, 1, 2)) {
1070                                // we only create cursor-backed result sets if
1071                                // a) The query is a SELECT
1072                                // b) The server supports it
1073                                // c) We know it is forward-only (note this doesn't
1074                                // preclude updatable result sets)
1075                                // d) The user has set a fetch size
1076                                if (this.resultFields != null &&
1077                                                this.connection.isCursorFetchEnabled()
1078                                                && getResultSetType() == ResultSet.TYPE_FORWARD_ONLY
1079                                                && getResultSetConcurrency() == ResultSet.CONCUR_READ_ONLY
1080                                                && getFetchSize() > 0) {
1081                                        packet.writeByte(MysqlDefs.OPEN_CURSOR_FLAG);
1082                                        usingCursor = true;
1083                                } else {
1084                                        packet.writeByte((byte) 0); // placeholder for flags
1085                                }
1086 
1087                                packet.writeLong(1); // placeholder for parameter
1088                                                     // iterations
1089                        }
1090 
1091                        /* Reserve place for null-marker bytes */
1092                        int nullCount = (this.parameterCount + 7) / 8;
1093 
1094                        // if (mysql.versionMeetsMinimum(4, 1, 2)) {
1095                        // nullCount = (this.parameterCount + 9) / 8;
1096                        // }
1097                        int nullBitsPosition = packet.getPosition();
1098 
1099                        for (int i = 0; i < nullCount; i++) {
1100                                packet.writeByte((byte) 0);
1101                        }
1102 
1103                        byte[] nullBitsBuffer = new byte[nullCount];
1104 
1105                        /* In case if buffers (type) altered, indicate to server */
1106                        packet.writeByte(this.sendTypesToServer ? (byte) 1 : (byte) 0);
1107 
1108                        if (this.sendTypesToServer) {
1109                                /*
1110                                 * Store types of parameters in first in first package that is
1111                                 * sent to the server.
1112                                 */
1113                                for (int i = 0; i < this.parameterCount; i++) {
1114                                        packet.writeInt(this.parameterBindings[i].bufferType);
1115                                }
1116                        }
1117 
1118                        //
1119                        // store the parameter values
1120                        //
1121                        for (int i = 0; i < this.parameterCount; i++) {
1122                                if (!this.parameterBindings[i].isLongData) {
1123                                        if (!this.parameterBindings[i].isNull) {
1124                                                storeBinding(packet, this.parameterBindings[i], mysql);
1125                                        } else {
1126                                                nullBitsBuffer[i / 8] |= (1 << (i & 7));
1127                                        }
1128                                }
1129                        }
1130 
1131                        //
1132                        // Go back and write the NULL flags
1133                        // to the beginning of the packet
1134                        //
1135                        int endPosition = packet.getPosition();
1136                        packet.setPosition(nullBitsPosition);
1137                        packet.writeBytesNoNull(nullBitsBuffer);
1138                        packet.setPosition(endPosition);
1139 
1140                        long begin = 0;
1141 
1142                        if (this.connection.getProfileSql()
1143                                        || this.connection.getLogSlowQueries()
1144                                        || this.connection.getGatherPerformanceMetrics()) {
1145                                begin = System.currentTimeMillis();
1146                        }
1147 
1148                        this.wasCancelled = false;
1149                        
1150                        CancelTask timeoutTask = null;
1151 
1152                        try {
1153                                if (this.timeout != 0
1154                                                && this.connection.versionMeetsMinimum(5, 0, 0)) {
1155                                        timeoutTask = new CancelTask();
1156                                        this.connection.getCancelTimer().schedule(timeoutTask, 
1157                                                        this.timeout);
1158                                }
1159                                
1160                                Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE,
1161                                        null, packet, false, null);
1162                                
1163                                if (timeoutTask != null) {
1164                                        timeoutTask.cancel();
1165                                        timeoutTask = null;
1166                                }
1167                                
1168                                if (this.wasCancelled) {
1169                                        this.wasCancelled = false;
1170                                        throw new MySQLTimeoutException();
1171                                }
1172                        
1173                                this.connection.incrementNumberOfPreparedExecutes();
1174        
1175                                if (this.connection.getProfileSql()) {
1176                                        this.eventSink = ProfileEventSink.getInstance(this.connection);
1177        
1178                                        this.eventSink.consumeEvent(new ProfilerEvent(
1179                                                        ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$
1180                                                        this.connectionId, this.statementId, -1, System
1181                                                                        .currentTimeMillis(), (int) (System
1182                                                                        .currentTimeMillis() - begin), null,
1183                                                        new Throwable(), truncateQueryToLog(asSql(true))));
1184                                }
1185        
1186                                com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this,
1187                                                maxRowsToRetrieve, this.resultSetType,
1188                                                this.resultSetConcurrency, createStreamingResultSet,
1189                                                this.currentCatalog, resultPacket, true, this.fieldCount,
1190                                                true);
1191        
1192                                
1193                                if (!createStreamingResultSet && 
1194                                                this.serverNeedsResetBeforeEachExecution) {
1195                                        serverResetStatement(); // clear any long data...
1196                                }
1197        
1198                                this.sendTypesToServer = false;
1199                                this.results = rs;
1200        
1201                                if (this.connection.getLogSlowQueries()
1202                                                || this.connection.getGatherPerformanceMetrics()) {
1203                                        long elapsedTime = System.currentTimeMillis() - begin;
1204        
1205                                        if (this.connection.getLogSlowQueries()
1206                                                        && (elapsedTime >= this.connection
1207                                                                        .getSlowQueryThresholdMillis())) {
1208                                                StringBuffer mesgBuf = new StringBuffer(
1209                                                                48 + this.originalSql.length());
1210                                                mesgBuf.append(Messages
1211                                                                .getString("ServerPreparedStatement.15")); //$NON-NLS-1$
1212                                                mesgBuf.append(this.connection
1213                                                                .getSlowQueryThresholdMillis());
1214                                                mesgBuf.append(Messages
1215                                                                .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$
1216                                                mesgBuf.append(elapsedTime);
1217                                                mesgBuf.append(Messages
1218                                                                .getString("ServerPreparedStatement.16")); //$NON-NLS-1$
1219                                                
1220                                                mesgBuf.append("as prepared: ");
1221                                                mesgBuf.append(this.originalSql);
1222                                                mesgBuf.append("\n\n with parameters bound:\n\n");
1223                                                mesgBuf.append(asSql(true));
1224        
1225                                                this.connection.getLog().logWarn(mesgBuf.toString());
1226        
1227                                                if (this.connection.getExplainSlowQueries()) {
1228                                                        String queryAsString = asSql(true);
1229        
1230                                                        mysql.explainSlowQuery(queryAsString.getBytes(),
1231                                                                        queryAsString);
1232                                                }
1233                                        }
1234        
1235                                        if (this.connection.getGatherPerformanceMetrics()) {
1236                                                this.connection.registerQueryExecutionTime(elapsedTime);
1237                                        }
1238                                }
1239                                
1240                                if (mysql.hadWarnings()) {
1241                            mysql.scanForAndThrowDataTruncation();
1242                        }
1243                                
1244                                return rs;
1245                        } finally {
1246                                if (timeoutTask != null) {
1247                                        timeoutTask.cancel();
1248                                }
1249                        }
1250                }
1251        }
1252 
1253 
1254        /**
1255         * Sends stream-type data parameters to the server.
1256         * 
1257         * <pre>
1258         * 
1259         *  Long data handling:
1260         * 
1261         *  - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
1262         *  - The packet recieved will have the format as:
1263         *    [COM_LONG_DATA:     1][STMT_ID:4][parameter_number:2][type:2][data]
1264         *  - Checks if the type is specified by client, and if yes reads the type,
1265         *    and  stores the data in that format.
1266         *  - It's up to the client to check for read data ended. The server doesn't
1267         *    care;  and also server doesn't notify to the client that it got the
1268         *    data  or not; if there is any error; then during execute; the error
1269         *    will  be returned
1270         *  
1271         * </pre>
1272         * 
1273         * @param parameterIndex
1274         *            DOCUMENT ME!
1275         * @param longData
1276         *            DOCUMENT ME!
1277         * 
1278         * @throws SQLException
1279         *             if an error occurs.
1280         */
1281        private void serverLongData(int parameterIndex, BindValue longData)
1282                        throws SQLException {
1283                synchronized (this.connection.getMutex()) {
1284                        MysqlIO mysql = this.connection.getIO();
1285 
1286                        Buffer packet = mysql.getSharedSendPacket();
1287 
1288                        Object value = longData.value;
1289 
1290                        if (value instanceof byte[]) {
1291                                packet.clear();
1292                                packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
1293                                packet.writeLong(this.serverStatementId);
1294                                packet.writeInt((parameterIndex));
1295 
1296                                packet.writeBytesNoNull((byte[]) longData.value);
1297 
1298                                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
1299                                                null);
1300                        } else if (value instanceof InputStream) {
1301                                storeStream(mysql, parameterIndex, packet, (InputStream) value);
1302                        } else if (value instanceof java.sql.Blob) {
1303                                storeStream(mysql, parameterIndex, packet,
1304                                                ((java.sql.Blob) value).getBinaryStream());
1305                        } else if (value instanceof Reader) {
1306                                storeReader(mysql, parameterIndex, packet, (Reader) value);
1307                        } else {
1308                                throw SQLError.createSQLException(Messages
1309                                                .getString("ServerPreparedStatement.18") //$NON-NLS-1$
1310                                                + value.getClass().getName() + "'", //$NON-NLS-1$
1311                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1312                        }
1313                }
1314        }
1315 
1316        private void serverPrepare(String sql) throws SQLException {
1317                synchronized (this.connection.getMutex()) {
1318                        MysqlIO mysql = this.connection.getIO();
1319 
1320                        if (this.connection.getAutoGenerateTestcaseScript()) {
1321                                dumpPrepareForTestcase();
1322                        }
1323 
1324                        try {
1325                                long begin = 0;
1326 
1327                                if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) { //$NON-NLS-1$
1328                                        this.isLoadDataQuery = true;
1329                                } else {
1330                                        this.isLoadDataQuery = false;
1331                                }
1332 
1333                                if (this.connection.getProfileSql()) {
1334                                        begin = System.currentTimeMillis();
1335                                }
1336 
1337                                String characterEncoding = null;
1338                                String connectionEncoding = this.connection.getEncoding();
1339 
1340                                if (!this.isLoadDataQuery && this.connection.getUseUnicode()
1341                                                && (connectionEncoding != null)) {
1342                                        characterEncoding = connectionEncoding;
1343                                }
1344 
1345                                Buffer prepareResultPacket = mysql.sendCommand(
1346                                                MysqlDefs.COM_PREPARE, sql, null, false,
1347                                                characterEncoding);
1348 
1349                                if (this.connection.versionMeetsMinimum(4, 1, 1)) {
1350                                        // 4.1.1 and newer use the first byte
1351                                        // as an 'ok' or 'error' flag, so move
1352                                        // the buffer pointer past it to
1353                                        // start reading the statement id.
1354                                        prepareResultPacket.setPosition(1);
1355                                } else {
1356                                        // 4.1.0 doesn't use the first byte as an
1357                                        // 'ok' or 'error' flag
1358                                        prepareResultPacket.setPosition(0);
1359                                }
1360 
1361                                this.serverStatementId = prepareResultPacket.readLong();
1362                                this.fieldCount = prepareResultPacket.readInt();
1363                                this.parameterCount = prepareResultPacket.readInt();
1364                                this.parameterBindings = new BindValue[this.parameterCount];
1365 
1366                                for (int i = 0; i < this.parameterCount; i++) {
1367                                        this.parameterBindings[i] = new BindValue();
1368                                }
1369 
1370                                this.connection.incrementNumberOfPrepares();
1371 
1372                                if (this.connection.getProfileSql()) {
1373                                        this.eventSink = ProfileEventSink
1374                                                        .getInstance(this.connection);
1375 
1376                                        this.eventSink.consumeEvent(new ProfilerEvent(
1377                                                        ProfilerEvent.TYPE_PREPARE,
1378                                                        "", this.currentCatalog, //$NON-NLS-1$
1379                                                        this.connectionId, this.statementId, -1,
1380                                                        System.currentTimeMillis(), (int) (System
1381                                                                        .currentTimeMillis() - begin), null,
1382                                                        new Throwable(), truncateQueryToLog(sql)));
1383                                }
1384 
1385                                if (this.parameterCount > 0) {
1386                                        if (this.connection.versionMeetsMinimum(4, 1, 2)
1387                                                        && !mysql.isVersion(5, 0, 0)) {
1388                                                this.parameterFields = new Field[this.parameterCount];
1389 
1390                                                Buffer metaDataPacket = mysql.readPacket();
1391 
1392                                                int i = 0;
1393 
1394                                                while (!metaDataPacket.isLastDataPacket()
1395                                                                && (i < this.parameterCount)) {
1396                                                        this.parameterFields[i++] = mysql.unpackField(
1397                                                                        metaDataPacket, false);
1398                                                        metaDataPacket = mysql.readPacket();
1399                                                }
1400                                        }
1401                                }
1402 
1403                                if (this.fieldCount > 0) {
1404                                        this.resultFields = new Field[this.fieldCount];
1405 
1406                                        Buffer fieldPacket = mysql.readPacket();
1407 
1408                                        int i = 0;
1409 
1410                                        // Read in the result set column information
1411                                        while (!fieldPacket.isLastDataPacket()
1412                                                        && (i < this.fieldCount)) {
1413                                                this.resultFields[i++] = mysql.unpackField(fieldPacket,
1414                                                                false);
1415                                                fieldPacket = mysql.readPacket();
1416                                        }
1417                                }
1418                        } catch (SQLException sqlEx) {
1419                                if (this.connection.getDumpQueriesOnException()) {
1420                                        StringBuffer messageBuf = new StringBuffer(this.originalSql
1421                                                        .length() + 32);
1422                                        messageBuf
1423                                                        .append("\n\nQuery being prepared when exception was thrown:\n\n");
1424                                        messageBuf.append(this.originalSql);
1425 
1426                                        sqlEx = Connection.appendMessageToException(sqlEx,
1427                                                        messageBuf.toString());
1428                                }
1429 
1430                                throw sqlEx;
1431                        } finally {
1432                                // Leave the I/O channel in a known state...there might be
1433                                // packets out there
1434                                // that we're not interested in
1435                                this.connection.getIO().clearInputStream();
1436                        }
1437                }
1438        }
1439 
1440        private String truncateQueryToLog(String sql) {
1441                String query = null;
1442                
1443                if (sql.length() > this.connection.getMaxQuerySizeToLog()) {
1444                        StringBuffer queryBuf = new StringBuffer(
1445                                        this.connection.getMaxQuerySizeToLog() + 12);
1446                        queryBuf.append(sql.substring(0, this.connection.getMaxQuerySizeToLog()));
1447                        queryBuf.append(Messages.getString("MysqlIO.25"));
1448                        
1449                        query = queryBuf.toString();
1450                } else {
1451                        query = sql;
1452                }
1453                
1454                return query;
1455        }
1456 
1457        private void serverResetStatement() throws SQLException {
1458                synchronized (this.connection.getMutex()) {
1459 
1460                        MysqlIO mysql = this.connection.getIO();
1461 
1462                        Buffer packet = mysql.getSharedSendPacket();
1463 
1464                        packet.clear();
1465                        packet.writeByte((byte) MysqlDefs.COM_RESET_STMT);
1466                        packet.writeLong(this.serverStatementId);
1467 
1468                        try {
1469                                mysql.sendCommand(MysqlDefs.COM_RESET_STMT, null, packet,
1470                                                !this.connection.versionMeetsMinimum(4, 1, 2), null);
1471                        } catch (SQLException sqlEx) {
1472                                throw sqlEx;
1473                        } catch (Exception ex) {
1474                                throw SQLError.createSQLException(ex.toString(),
1475                                                SQLError.SQL_STATE_GENERAL_ERROR);
1476                        } finally {
1477                                mysql.clearInputStream();
1478                        }
1479                }
1480        }
1481 
1482        /**
1483         * @see java.sql.PreparedStatement#setArray(int, java.sql.Array)
1484         */
1485        public void setArray(int i, Array x) throws SQLException {
1486                throw new NotImplemented();
1487        }
1488 
1489        /**
1490         * @see java.sql.PreparedStatement#setAsciiStream(int, java.io.InputStream,
1491         *      int)
1492         */
1493        public void setAsciiStream(int parameterIndex, InputStream x, int length)
1494                        throws SQLException {
1495                checkClosed();
1496 
1497                if (x == null) {
1498                        setNull(parameterIndex, java.sql.Types.BINARY);
1499                } else {
1500                        BindValue binding = getBinding(parameterIndex, true);
1501                        setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1502 
1503                        binding.value = x;
1504                        binding.isNull = false;
1505                        binding.isLongData = true;
1506 
1507                        if (this.connection.getUseStreamLengthsInPrepStmts()) {
1508                                binding.bindLength = length;
1509                        } else {
1510                                binding.bindLength = -1;
1511                        }
1512                }
1513        }
1514 
1515        /**
1516         * @see java.sql.PreparedStatement#setBigDecimal(int, java.math.BigDecimal)
1517         */
1518        public void setBigDecimal(int parameterIndex, BigDecimal x)
1519                        throws SQLException {
1520                checkClosed();
1521 
1522                if (x == null) {
1523                        setNull(parameterIndex, java.sql.Types.DECIMAL);
1524                } else {
1525                        setString(parameterIndex, StringUtils.fixDecimalExponent(x
1526                                        .toString()));
1527                }
1528        }
1529 
1530        /**
1531         * @see java.sql.PreparedStatement#setBinaryStream(int, java.io.InputStream,
1532         *      int)
1533         */
1534        public void setBinaryStream(int parameterIndex, InputStream x, int length)
1535                        throws SQLException {
1536                checkClosed();
1537 
1538                if (x == null) {
1539                        setNull(parameterIndex, java.sql.Types.BINARY);
1540                } else {
1541                        BindValue binding = getBinding(parameterIndex, true);
1542                        setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1543 
1544                        binding.value = x;
1545                        binding.isNull = false;
1546                        binding.isLongData = true;
1547 
1548                        if (this.connection.getUseStreamLengthsInPrepStmts()) {
1549                                binding.bindLength = length;
1550                        } else {
1551                                binding.bindLength = -1;
1552                        }
1553                }
1554        }
1555 
1556        /**
1557         * @see java.sql.PreparedStatement#setBlob(int, java.sql.Blob)
1558         */
1559        public void setBlob(int parameterIndex, Blob x) throws SQLException {
1560                checkClosed();
1561 
1562                if (x == null) {
1563                        setNull(parameterIndex, java.sql.Types.BINARY);
1564                } else {
1565                        BindValue binding = getBinding(parameterIndex, true);
1566                        setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1567 
1568                        binding.value = x;
1569                        binding.isNull = false;
1570                        binding.isLongData = true;
1571 
1572                        if (this.connection.getUseStreamLengthsInPrepStmts()) {
1573                                binding.bindLength = x.length();
1574                        } else {
1575                                binding.bindLength = -1;
1576                        }
1577                }
1578        }
1579 
1580        /**
1581         * @see java.sql.PreparedStatement#setBoolean(int, boolean)
1582         */
1583        public void setBoolean(int parameterIndex, boolean x) throws SQLException {
1584                setByte(parameterIndex, (x ? (byte) 1 : (byte) 0));
1585        }
1586 
1587        /**
1588         * @see java.sql.PreparedStatement#setByte(int, byte)
1589         */
1590        public void setByte(int parameterIndex, byte x) throws SQLException {
1591                checkClosed();
1592 
1593                BindValue binding = getBinding(parameterIndex, false);
1594                setType(binding, MysqlDefs.FIELD_TYPE_TINY);
1595 
1596                binding.value = null;
1597                binding.byteBinding = x;
1598                binding.isNull = false;
1599                binding.isLongData = false;
1600        }
1601 
1602        /**
1603         * @see java.sql.PreparedStatement#setBytes(int, byte)
1604         */
1605        public void setBytes(int parameterIndex, byte[] x) throws SQLException {
1606                checkClosed();
1607 
1608                if (x == null) {
1609                        setNull(parameterIndex, java.sql.Types.BINARY);
1610                } else {
1611                        BindValue binding = getBinding(parameterIndex, false);
1612                        setType(binding, MysqlDefs.FIELD_TYPE_VAR_STRING);
1613 
1614                        binding.value = x;
1615                        binding.isNull = false;
1616                        binding.isLongData = false;
1617                }
1618        }
1619 
1620        /**
1621         * @see java.sql.PreparedStatement#setCharacterStream(int, java.io.Reader,
1622         *      int)
1623         */
1624        public void setCharacterStream(int parameterIndex, Reader reader, int length)
1625                        throws SQLException {
1626                checkClosed();
1627 
1628                if (reader == null) {
1629                        setNull(parameterIndex, java.sql.Types.BINARY);
1630                } else {
1631                        BindValue binding = getBinding(parameterIndex, true);
1632                        setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1633 
1634                        binding.value = reader;
1635                        binding.isNull = false;
1636                        binding.isLongData = true;
1637 
1638                        if (this.connection.getUseStreamLengthsInPrepStmts()) {
1639                                binding.bindLength = length;
1640                        } else {
1641                                binding.bindLength = -1;
1642                        }
1643                }
1644        }
1645 
1646        /**
1647         * @see java.sql.PreparedStatement#setClob(int, java.sql.Clob)
1648         */
1649        public void setClob(int parameterIndex, Clob x) throws SQLException {
1650                checkClosed();
1651 
1652                if (x == null) {
1653                        setNull(parameterIndex, java.sql.Types.BINARY);
1654                } else {
1655                        BindValue binding = getBinding(parameterIndex, true);
1656                        setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1657 
1658                        binding.value = x.getCharacterStream();
1659                        binding.isNull = false;
1660                        binding.isLongData = true;
1661 
1662                        if (this.connection.getUseStreamLengthsInPrepStmts()) {
1663                                binding.bindLength = x.length();
1664                        } else {
1665                                binding.bindLength = -1;
1666                        }
1667                }
1668        }
1669 
1670        /**
1671         * Set a parameter to a java.sql.Date value. The driver converts this to a
1672         * SQL DATE value when it sends it to the database.
1673         * 
1674         * @param parameterIndex
1675         *            the first parameter is 1, the second is 2, ...
1676         * @param x
1677         *            the parameter value
1678         * 
1679         * @exception SQLException
1680         *                if a database-access error occurs.
1681         */
1682        public void setDate(int parameterIndex, Date x) throws SQLException {
1683                setDate(parameterIndex, x, null);
1684        }
1685 
1686        /**
1687         * Set a parameter to a java.sql.Date value. The driver converts this to a
1688         * SQL DATE value when it sends it to the database.
1689         * 
1690         * @param parameterIndex
1691         *            the first parameter is 1, the second is 2, ...
1692         * @param x
1693         *            the parameter value
1694         * @param cal
1695         *            the calendar to interpret the date with
1696         * 
1697         * @exception SQLException
1698         *                if a database-access error occurs.
1699         */
1700        public void setDate(int parameterIndex, Date x, Calendar cal)
1701                        throws SQLException {
1702                if (x == null) {
1703                        setNull(parameterIndex, java.sql.Types.DATE);
1704                } else {
1705                        BindValue binding = getBinding(parameterIndex, false);
1706                        setType(binding, MysqlDefs.FIELD_TYPE_DATE);
1707 
1708                        binding.value = x;
1709                        binding.isNull = false;
1710                        binding.isLongData = false;
1711                }
1712        }
1713 
1714        /**
1715         * @see java.sql.PreparedStatement#setDouble(int, double)
1716         */
1717        public void setDouble(int parameterIndex, double x) throws SQLException {
1718                checkClosed();
1719 
1720                if (!this.connection.getAllowNanAndInf()
1721                                && (x == Double.POSITIVE_INFINITY
1722                                                || x == Double.NEGATIVE_INFINITY || Double.isNaN(x))) {
1723                        throw SQLError.createSQLException("'" + x
1724                                        + "' is not a valid numeric or approximate numeric value",
1725                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1726 
1727                }
1728 
1729                BindValue binding = getBinding(parameterIndex, false);
1730                setType(binding, MysqlDefs.FIELD_TYPE_DOUBLE);
1731 
1732                binding.value = null;
1733                binding.doubleBinding = x;
1734                binding.isNull = false;
1735                binding.isLongData = false;
1736        }
1737 
1738        /**
1739         * @see java.sql.PreparedStatement#setFloat(int, float)
1740         */
1741        public void setFloat(int parameterIndex, float x) throws SQLException {
1742                checkClosed();
1743 
1744                BindValue binding = getBinding(parameterIndex, false);
1745                setType(binding, MysqlDefs.FIELD_TYPE_FLOAT);
1746 
1747                binding.value = null;
1748                binding.floatBinding = x;
1749                binding.isNull = false;
1750                binding.isLongData = false;
1751        }
1752 
1753        /**
1754         * @see java.sql.PreparedStatement#setInt(int, int)
1755         */
1756        public void setInt(int parameterIndex, int x) throws SQLException {
1757                checkClosed();
1758 
1759                BindValue binding = getBinding(parameterIndex, false);
1760                setType(binding, MysqlDefs.FIELD_TYPE_LONG);
1761 
1762                binding.value = null;
1763                binding.intBinding = x;
1764                binding.isNull = false;
1765                binding.isLongData = false;
1766        }
1767 
1768        /**
1769         * @see java.sql.PreparedStatement#setLong(int, long)
1770         */
1771        public void setLong(int parameterIndex, long x) throws SQLException {
1772                checkClosed();
1773 
1774                BindValue binding = getBinding(parameterIndex, false);
1775                setType(binding, MysqlDefs.FIELD_TYPE_LONGLONG);
1776 
1777                binding.value = null;
1778                binding.longBinding = x;
1779                binding.isNull = false;
1780                binding.isLongData = false;
1781        }
1782 
1783        /**
1784         * @see java.sql.PreparedStatement#setNull(int, int)
1785         */
1786        public void setNull(int parameterIndex, int sqlType) throws SQLException {
1787                checkClosed();
1788 
1789                BindValue binding = getBinding(parameterIndex, false);
1790 
1791                //
1792                // Don't re-set types, but use something if this
1793                // parameter was never specified
1794                //
1795                if (binding.bufferType == 0) {
1796                        setType(binding, MysqlDefs.FIELD_TYPE_NULL);
1797                }
1798 
1799                binding.value = null;
1800                binding.isNull = true;
1801                binding.isLongData = false;
1802        }
1803 
1804        /**
1805         * @see java.sql.PreparedStatement#setNull(int, int, java.lang.String)
1806         */
1807        public void setNull(int parameterIndex, int sqlType, String typeName)
1808                        throws SQLException {
1809                checkClosed();
1810 
1811                BindValue binding = getBinding(parameterIndex, false);
1812 
1813                //
1814                // Don't re-set types, but use something if this
1815                // parameter was never specified
1816                //
1817                if (binding.bufferType == 0) {
1818                        setType(binding, MysqlDefs.FIELD_TYPE_NULL);
1819                }
1820 
1821                binding.value = null;
1822                binding.isNull = true;
1823                binding.isLongData = false;
1824        }
1825 
1826        /**
1827         * @see java.sql.PreparedStatement#setRef(int, java.sql.Ref)
1828         */
1829        public void setRef(int i, Ref x) throws SQLException {
1830                throw new NotImplemented();
1831        }
1832 
1833        /**
1834         * @see java.sql.PreparedStatement#setShort(int, short)
1835         */
1836        public void setShort(int parameterIndex, short x) throws SQLException {
1837                checkClosed();
1838 
1839                BindValue binding = getBinding(parameterIndex, false);
1840                setType(binding, MysqlDefs.FIELD_TYPE_SHORT);
1841 
1842                binding.value = null;
1843                binding.shortBinding = x;
1844                binding.isNull = false;
1845                binding.isLongData = false;
1846        }
1847 
1848        /**
1849         * @see java.sql.PreparedStatement#setString(int, java.lang.String)
1850         */
1851        public void setString(int parameterIndex, String x) throws SQLException {
1852                checkClosed();
1853 
1854                if (x == null) {
1855                        setNull(parameterIndex, java.sql.Types.CHAR);
1856                } else {
1857                        BindValue binding = getBinding(parameterIndex, false);
1858 
1859                        setType(binding, this.stringTypeCode);
1860 
1861                        binding.value = x;
1862                        binding.isNull = false;
1863                        binding.isLongData = false;
1864                }
1865        }
1866 
1867        /**
1868         * Set a parameter to a java.sql.Time value.
1869         * 
1870         * @param parameterIndex
1871         *            the first parameter is 1...));
1872         * @param x
1873         *            the parameter value
1874         * 
1875         * @throws SQLException
1876         *             if a database access error occurs
1877         */
1878        public void setTime(int parameterIndex, java.sql.Time x)
1879                        throws SQLException {
1880                setTimeInternal(parameterIndex, x, null, TimeZone.getDefault(), false);
1881        }
1882 
1883        /**
1884         * Set a parameter to a java.sql.Time value. The driver converts this to a
1885         * SQL TIME value when it sends it to the database, using the given
1886         * timezone.
1887         * 
1888         * @param parameterIndex
1889         *            the first parameter is 1...));
1890         * @param x
1891         *            the parameter value
1892         * @param cal
1893         *            the timezone to use
1894         * 
1895         * @throws SQLException
1896         *             if a database access error occurs
1897         */
1898        public void setTime(int parameterIndex, java.sql.Time x, Calendar cal)
1899                        throws SQLException {
1900                setTimeInternal(parameterIndex, x, cal, cal.getTimeZone(), true);
1901        }
1902 
1903        /**
1904         * Set a parameter to a java.sql.Time value. The driver converts this to a
1905         * SQL TIME value when it sends it to the database, using the given
1906         * timezone.
1907         * 
1908         * @param parameterIndex
1909         *            the first parameter is 1...));
1910         * @param x
1911         *            the parameter value
1912         * @param tz
1913         *            the timezone to use
1914         * 
1915         * @throws SQLException
1916         *             if a database access error occurs
1917         */
1918        public void setTimeInternal(int parameterIndex, java.sql.Time x,
1919                        Calendar targetCalendar,
1920                        TimeZone tz, boolean rollForward) throws SQLException {
1921                if (x == null) {
1922                        setNull(parameterIndex, java.sql.Types.TIME);
1923                } else {
1924                        BindValue binding = getBinding(parameterIndex, false);
1925                        setType(binding, MysqlDefs.FIELD_TYPE_TIME);
1926 
1927                        Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
1928                        
1929                        synchronized (sessionCalendar) {
1930                                binding.value = TimeUtil.changeTimezone(this.connection, 
1931                                                sessionCalendar,
1932                                                targetCalendar,
1933                                                x, tz,
1934                                                this.connection.getServerTimezoneTZ(), 
1935                                                rollForward);
1936                        }
1937                        
1938                        binding.isNull = false;
1939                        binding.isLongData = false;
1940                }
1941        }
1942 
1943        /**
1944         * Set a parameter to a java.sql.Timestamp value. The driver converts this
1945         * to a SQL TIMESTAMP value when it sends it to the database.
1946         * 
1947         * @param parameterIndex
1948         *            the first parameter is 1, the second is 2, ...
1949         * @param x
1950         *            the parameter value
1951         * 
1952         * @throws SQLException
1953         *             if a database-access error occurs.
1954         */
1955        public void setTimestamp(int parameterIndex, java.sql.Timestamp x)
1956                        throws SQLException {
1957                setTimestampInternal(parameterIndex, x, null, TimeZone.getDefault(), false);
1958        }
1959 
1960        /**
1961         * Set a parameter to a java.sql.Timestamp value. The driver converts this
1962         * to a SQL TIMESTAMP value when it sends it to the database.
1963         * 
1964         * @param parameterIndex
1965         *            the first parameter is 1, the second is 2, ...
1966         * @param x
1967         *            the parameter value
1968         * @param cal
1969         *            the timezone to use
1970         * 
1971         * @throws SQLException
1972         *             if a database-access error occurs.
1973         */
1974        public void setTimestamp(int parameterIndex, java.sql.Timestamp x,
1975                        Calendar cal) throws SQLException {
1976                setTimestampInternal(parameterIndex, x, cal, cal.getTimeZone(), true);
1977        }
1978 
1979        protected void setTimestampInternal(int parameterIndex,
1980                        java.sql.Timestamp x, Calendar targetCalendar,
1981                        TimeZone tz, boolean rollForward)
1982                        throws SQLException {
1983                if (x == null) {
1984                        setNull(parameterIndex, java.sql.Types.TIMESTAMP);
1985                } else {
1986                        BindValue binding = getBinding(parameterIndex, false);
1987                        setType(binding, MysqlDefs.FIELD_TYPE_DATETIME);
1988 
1989                        Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ?
1990                                        this.connection.getUtcCalendar() : 
1991                                                getCalendarInstanceForSessionOrNew();
1992                        
1993                        synchronized (sessionCalendar) {
1994                                binding.value = TimeUtil.changeTimezone(this.connection, 
1995                                                sessionCalendar,
1996                                                targetCalendar,
1997                                                x, tz,
1998                                                this.connection.getServerTimezoneTZ(), 
1999                                                rollForward);
2000                        }
2001                        
2002                        binding.isNull = false;
2003                        binding.isLongData = false;
2004                }
2005        }
2006 
2007        private void setType(BindValue oldValue, int bufferType) {
2008                if (oldValue.bufferType != bufferType) {
2009                        this.sendTypesToServer = true;
2010                }
2011 
2012                oldValue.bufferType = bufferType;
2013        }
2014 
2015        /**
2016         * DOCUMENT ME!
2017         * 
2018         * @param parameterIndex
2019         *            DOCUMENT ME!
2020         * @param x
2021         *            DOCUMENT ME!
2022         * @param length
2023         *            DOCUMENT ME!
2024         * 
2025         * @throws SQLException
2026         *             DOCUMENT ME!
2027         * @throws NotImplemented
2028         *             DOCUMENT ME!
2029         * 
2030         * @see java.sql.PreparedStatement#setUnicodeStream(int,
2031         *      java.io.InputStream, int)
2032         * @deprecated
2033         */
2034        public void setUnicodeStream(int parameterIndex, InputStream x, int length)
2035                        throws SQLException {
2036                checkClosed();
2037 
2038                throw new NotImplemented();
2039        }
2040 
2041        /**
2042         * @see java.sql.PreparedStatement#setURL(int, java.net.URL)
2043         */
2044        public void setURL(int parameterIndex, URL x) throws SQLException {
2045                checkClosed();
2046 
2047                setString(parameterIndex, x.toString());
2048        }
2049 
2050        /**
2051         * Method storeBinding.
2052         * 
2053         * @param packet
2054         * @param bindValue
2055         * @param mysql
2056         *            DOCUMENT ME!
2057         * 
2058         * @throws SQLException
2059         *             DOCUMENT ME!
2060         */
2061        private void storeBinding(Buffer packet, BindValue bindValue, MysqlIO mysql)
2062                        throws SQLException {
2063                try {
2064                        Object value = bindValue.value;
2065 
2066                        //
2067                        // Handle primitives first
2068                        //
2069                        switch (bindValue.bufferType) {
2070 
2071                        case MysqlDefs.FIELD_TYPE_TINY:
2072                                packet.writeByte(bindValue.byteBinding);
2073                                return;
2074                        case MysqlDefs.FIELD_TYPE_SHORT:
2075                                packet.ensureCapacity(2);
2076                                packet.writeInt(bindValue.shortBinding);
2077                                return;
2078                        case MysqlDefs.FIELD_TYPE_LONG:
2079                                packet.ensureCapacity(4);
2080                                packet.writeLong(bindValue.intBinding);
2081                                return;
2082                        case MysqlDefs.FIELD_TYPE_LONGLONG:
2083                                packet.ensureCapacity(8);
2084                                packet.writeLongLong(bindValue.longBinding);
2085                                return;
2086                        case MysqlDefs.FIELD_TYPE_FLOAT:
2087                                packet.ensureCapacity(4);
2088                                packet.writeFloat(bindValue.floatBinding);
2089                                return;
2090                        case MysqlDefs.FIELD_TYPE_DOUBLE:
2091                                packet.ensureCapacity(8);
2092                                packet.writeDouble(bindValue.doubleBinding);
2093                                return;
2094                        case MysqlDefs.FIELD_TYPE_TIME:
2095                                storeTime(packet, (Time) value);
2096                                return;
2097                        case MysqlDefs.FIELD_TYPE_DATE:
2098                        case MysqlDefs.FIELD_TYPE_DATETIME:
2099                        case MysqlDefs.FIELD_TYPE_TIMESTAMP:
2100                                storeDateTime(packet, (java.util.Date) value, mysql);
2101                                return;
2102                        case MysqlDefs.FIELD_TYPE_VAR_STRING:
2103                        case MysqlDefs.FIELD_TYPE_STRING:
2104                        case MysqlDefs.FIELD_TYPE_VARCHAR:
2105                                if (value instanceof byte[]) {
2106                                        packet.writeLenBytes((byte[]) value);
2107                                } else if (!this.isLoadDataQuery) {
2108                                        packet.writeLenString((String) value, this.charEncoding,
2109                                                        this.connection.getServerCharacterEncoding(),
2110                                                        this.charConverter, this.connection
2111                                                                        .parserKnowsUnicode(),
2112                                                                        this.connection);
2113                                } else {
2114                                        packet.writeLenBytes(((String) value).getBytes());
2115                                }
2116 
2117                                return;
2118                        }
2119 
2120                        
2121                } catch (UnsupportedEncodingException uEE) {
2122                        throw SQLError.createSQLException(Messages
2123                                        .getString("ServerPreparedStatement.22") //$NON-NLS-1$
2124                                        + this.connection.getEncoding() + "'", //$NON-NLS-1$
2125                                        SQLError.SQL_STATE_GENERAL_ERROR);
2126                }
2127        }
2128 
2129        private void storeDataTime412AndOlder(Buffer intoBuf, java.util.Date dt)
2130                        throws SQLException {
2131                
2132                Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
2133                
2134                synchronized (sessionCalendar) {
2135                        java.util.Date oldTime = sessionCalendar.getTime();
2136                        
2137                        try {
2138                                intoBuf.ensureCapacity(8);
2139                                intoBuf.writeByte((byte) 7); // length
2140        
2141                                sessionCalendar.setTime(dt);
2142                                
2143                                int year = sessionCalendar.get(Calendar.YEAR);
2144                                int month = sessionCalendar.get(Calendar.MONTH) + 1;
2145                                int date = sessionCalendar.get(Calendar.DATE);
2146 
2147                                intoBuf.writeInt(year);
2148                                intoBuf.writeByte((byte) month);
2149                                intoBuf.writeByte((byte) date);
2150                
2151                                if (dt instanceof java.sql.Date) {
2152                                        intoBuf.writeByte((byte) 0);
2153                                        intoBuf.writeByte((byte) 0);
2154                                        intoBuf.writeByte((byte) 0);
2155                                } else {
2156                                        intoBuf.writeByte((byte) sessionCalendar
2157                                                        .get(Calendar.HOUR_OF_DAY));
2158                                        intoBuf.writeByte((byte) sessionCalendar
2159                                                        .get(Calendar.MINUTE));
2160                                        intoBuf.writeByte((byte) sessionCalendar
2161                                                        .get(Calendar.SECOND));
2162                                }
2163                        } finally {
2164                                sessionCalendar.setTime(oldTime);
2165                        }
2166                }
2167        }
2168 
2169        private void storeDateTime(Buffer intoBuf, java.util.Date dt, MysqlIO mysql)
2170                        throws SQLException {
2171                if (this.connection.versionMeetsMinimum(4, 1, 3)) {
2172                        storeDateTime413AndNewer(intoBuf, dt);
2173                } else {
2174                        storeDataTime412AndOlder(intoBuf, dt);
2175                }
2176        }
2177 
2178        private void storeDateTime413AndNewer(Buffer intoBuf, java.util.Date dt)
2179                        throws SQLException {
2180                Calendar sessionCalendar = (dt instanceof Timestamp && 
2181                                this.connection.getUseJDBCCompliantTimezoneShift()) ? 
2182                                this.connection.getUtcCalendar() : getCalendarInstanceForSessionOrNew();
2183                
2184                synchronized (sessionCalendar) {
2185                        java.util.Date oldTime = sessionCalendar.getTime();
2186                
2187                
2188                        try {
2189                                sessionCalendar.setTime(dt);
2190                                
2191                                if (dt instanceof java.sql.Date) {
2192                                        sessionCalendar.set(Calendar.HOUR_OF_DAY, 0);
2193                                        sessionCalendar.set(Calendar.MINUTE, 0);
2194                                        sessionCalendar.set(Calendar.SECOND, 0);
2195                                }
2196 
2197                                byte length = (byte) 7;
2198 
2199                                intoBuf.ensureCapacity(length);
2200 
2201                                if (dt instanceof java.sql.Timestamp) {
2202                                        length = (byte) 11;
2203                                }
2204 
2205                                intoBuf.writeByte(length); // length
2206 
2207                                int year = sessionCalendar.get(Calendar.YEAR);
2208                                int month = sessionCalendar.get(Calendar.MONTH) + 1;
2209                                int date = sessionCalendar.get(Calendar.DAY_OF_MONTH);
2210                                
2211                                intoBuf.writeInt(year);
2212                                intoBuf.writeByte((byte) month);
2213                                intoBuf.writeByte((byte) date);
2214 
2215                                if (dt instanceof java.sql.Date) {
2216                                        intoBuf.writeByte((byte) 0);
2217                                        intoBuf.writeByte((byte) 0);
2218                                        intoBuf.writeByte((byte) 0);
2219                                } else {
2220                                        intoBuf.writeByte((byte) sessionCalendar
2221                                                        .get(Calendar.HOUR_OF_DAY));
2222                                        intoBuf.writeByte((byte) sessionCalendar
2223                                                        .get(Calendar.MINUTE));
2224                                        intoBuf.writeByte((byte) sessionCalendar
2225                                                        .get(Calendar.SECOND));
2226                                }
2227 
2228                                if (length == 11) {
2229                                        intoBuf.writeLong(((java.sql.Timestamp) dt).getNanos());
2230                                }
2231                        
2232                        } finally {
2233                                sessionCalendar.setTime(oldTime);
2234                        }
2235                }
2236        }
2237 
2238        //
2239        // TO DO: Investigate using NIO to do this faster
2240        //
2241        private void storeReader(MysqlIO mysql, int parameterIndex, Buffer packet,
2242                        Reader inStream) throws SQLException {
2243                String forcedEncoding = this.connection.getClobCharacterEncoding();
2244                
2245                String clobEncoding = 
2246                        (forcedEncoding == null ? this.connection.getEncoding() : forcedEncoding);
2247                
2248                int maxBytesChar = 2;
2249                        
2250                if (clobEncoding != null) {
2251                        if (!clobEncoding.equals("UTF-16")) {
2252                                maxBytesChar = this.connection.getMaxBytesPerChar(clobEncoding);
2253                                
2254                                if (maxBytesChar == 1) {
2255                                        maxBytesChar = 2; // for safety
2256                                }
2257                        } else {
2258                                maxBytesChar = 4;
2259                        }
2260                }
2261                        
2262                char[] buf = new char[BLOB_STREAM_READ_BUF_SIZE / maxBytesChar];
2263                
2264                int numRead = 0;
2265 
2266                int bytesInPacket = 0;
2267                int totalBytesRead = 0;
2268                int bytesReadAtLastSend = 0;
2269                int packetIsFullAt = this.connection.getBlobSendChunkSize();
2270                
2271                
2272                
2273                try {
2274                        packet.clear();
2275                        packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2276                        packet.writeLong(this.serverStatementId);
2277                        packet.writeInt((parameterIndex));
2278 
2279                        boolean readAny = false;
2280                        
2281                        while ((numRead = inStream.read(buf)) != -1) {
2282                                readAny = true;
2283                        
2284                                byte[] valueAsBytes = StringUtils.getBytes(buf, null,
2285                                                clobEncoding, this.connection
2286                                                                .getServerCharacterEncoding(), 0, numRead,
2287                                                this.connection.parserKnowsUnicode());
2288 
2289                                packet.writeBytesNoNull(valueAsBytes, 0, valueAsBytes.length);
2290 
2291                                bytesInPacket += valueAsBytes.length;
2292                                totalBytesRead += valueAsBytes.length;
2293 
2294                                if (bytesInPacket >= packetIsFullAt) {
2295                                        bytesReadAtLastSend = totalBytesRead;
2296 
2297                                        mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet,
2298                                                        true, null);
2299 
2300                                        bytesInPacket = 0;
2301                                        packet.clear();
2302                                        packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2303                                        packet.writeLong(this.serverStatementId);
2304                                        packet.writeInt((parameterIndex));
2305                                }
2306                        }
2307 
2308                        if (totalBytesRead != bytesReadAtLastSend) {
2309                                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2310                                                null);
2311                        }
2312                        
2313                        if (!readAny) {
2314                                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2315                                                null);
2316                        }
2317                } catch (IOException ioEx) {
2318                        throw SQLError.createSQLException(Messages
2319                                        .getString("ServerPreparedStatement.24") //$NON-NLS-1$
2320                                        + ioEx.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
2321                } finally {
2322                        if (this.connection.getAutoClosePStmtStreams()) {
2323                                if (inStream != null) {
2324                                        try {
2325                                                inStream.close();
2326                                        } catch (IOException ioEx) {
2327                                                ; // ignore
2328                                        }
2329                                }
2330                        }
2331                }
2332        }
2333 
2334        private void storeStream(MysqlIO mysql, int parameterIndex, Buffer packet,
2335                        InputStream inStream) throws SQLException {
2336                byte[] buf = new byte[BLOB_STREAM_READ_BUF_SIZE];
2337 
2338                int numRead = 0;
2339                
2340                try {
2341                        int bytesInPacket = 0;
2342                        int totalBytesRead = 0;
2343                        int bytesReadAtLastSend = 0;
2344                        int packetIsFullAt = this.connection.getBlobSendChunkSize();
2345 
2346                        packet.clear();
2347                        packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2348                        packet.writeLong(this.serverStatementId);
2349                        packet.writeInt((parameterIndex));
2350 
2351                        boolean readAny = false;
2352                        
2353                        while ((numRead = inStream.read(buf)) != -1) {
2354 
2355                                readAny = true;
2356                                
2357                                packet.writeBytesNoNull(buf, 0, numRead);
2358                                bytesInPacket += numRead;
2359                                totalBytesRead += numRead;
2360 
2361                                if (bytesInPacket >= packetIsFullAt) {
2362                                        bytesReadAtLastSend = totalBytesRead;
2363 
2364                                        mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet,
2365                                                        true, null);
2366 
2367                                        bytesInPacket = 0;
2368                                        packet.clear();
2369                                        packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2370                                        packet.writeLong(this.serverStatementId);
2371                                        packet.writeInt((parameterIndex));
2372                                }
2373                        }
2374 
2375                        if (totalBytesRead != bytesReadAtLastSend) {
2376                                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2377                                                null);
2378                        }
2379                        
2380                        if (!readAny) {
2381                                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2382                                                null);
2383                        }
2384                } catch (IOException ioEx) {
2385                        throw SQLError.createSQLException(Messages
2386                                        .getString("ServerPreparedStatement.25") //$NON-NLS-1$
2387                                        + ioEx.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
2388                } finally {
2389                        if (this.connection.getAutoClosePStmtStreams()) {
2390                                if (inStream != null) {
2391                                        try {
2392                                                inStream.close();
2393                                        } catch (IOException ioEx) {
2394                                                ; // ignore
2395                                        }
2396                                }
2397                        }
2398                }
2399        }
2400 
2401        /**
2402         * @see java.lang.Object#toString()
2403         */
2404        public String toString() {
2405                StringBuffer toStringBuf = new StringBuffer();
2406 
2407                toStringBuf.append("com.mysql.jdbc.ServerPreparedStatement["); //$NON-NLS-1$
2408                toStringBuf.append(this.serverStatementId);
2409                toStringBuf.append("] - "); //$NON-NLS-1$
2410 
2411                try {
2412                        toStringBuf.append(asSql());
2413                } catch (SQLException sqlEx) {
2414                        toStringBuf.append(Messages.getString("ServerPreparedStatement.6")); //$NON-NLS-1$
2415                        toStringBuf.append(sqlEx);
2416                }
2417 
2418                return toStringBuf.toString();
2419        }
2420 
2421        protected long getServerStatementId() {
2422                return serverStatementId;
2423        }
2424}

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