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

COVERAGE SUMMARY FOR SOURCE FILE [ServerPreparedStatement.java]

nameclass, %method, %block, %line, %
ServerPreparedStatement.java100% (3/3)82%  (58/71)78%  (2909/3751)77%  (693.2/898)

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

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