KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mysql > jdbc > ServerPreparedStatement


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  */

25 package com.mysql.jdbc;
26
27 import com.mysql.jdbc.profiler.ProfileEventSink;
28 import com.mysql.jdbc.profiler.ProfilerEvent;
29
30 import java.io.IOException JavaDoc;
31 import java.io.InputStream JavaDoc;
32 import java.io.Reader JavaDoc;
33 import java.io.UnsupportedEncodingException JavaDoc;
34
35 import java.math.BigDecimal JavaDoc;
36
37 import java.net.URL JavaDoc;
38
39 import java.sql.Array JavaDoc;
40 import java.sql.Blob JavaDoc;
41 import java.sql.Clob JavaDoc;
42 import java.sql.Date JavaDoc;
43 import java.sql.ParameterMetaData JavaDoc;
44 import java.sql.Ref JavaDoc;
45 import java.sql.SQLException JavaDoc;
46 import java.sql.Time JavaDoc;
47 import java.sql.Types JavaDoc;
48
49 import java.util.ArrayList JavaDoc;
50 import java.util.BitSet JavaDoc;
51 import java.util.Calendar JavaDoc;
52 import java.util.Locale JavaDoc;
53 import java.util.TimeZone JavaDoc;
54
55 /**
56  * JDBC Interface for MySQL-4.1 and newer server-side PreparedStatements.
57  *
58  * @author Mark Matthews
59  * @version $Id: ServerPreparedStatement.java,v 1.1.2.2 2005/05/17 14:58:56
60  * mmatthews Exp $
61  */

62 public class ServerPreparedStatement extends PreparedStatement {
63     static class BatchedBindValues {
64         BindValue[] batchedParameterValues;
65
66         BatchedBindValues(BindValue[] paramVals) {
67             int numParams = paramVals.length;
68
69             this.batchedParameterValues = new BindValue[numParams];
70
71             for (int i = 0; i < numParams; i++) {
72                 this.batchedParameterValues[i] = new BindValue(paramVals[i]);
73             }
74         }
75     }
76
77     static class BindValue {
78
79         long bindLength; /* Default length of data */
80
81         int bufferType; /* buffer type */
82
83         byte byteBinding;
84
85         double doubleBinding;
86
87         float floatBinding;
88
89         int intBinding;
90
91         boolean isLongData; /* long data indicator */
92
93         boolean isNull; /* NULL indicator */
94
95         boolean isSet = false; /* has this parameter been set? */
96
97         long longBinding;
98
99         short shortBinding;
100
101         Object JavaDoc value; /* The value to store */
102
103         BindValue() {
104         }
105
106         BindValue(BindValue copyMe) {
107             this.value = copyMe.value;
108             this.isSet = copyMe.isSet;
109             this.isLongData = copyMe.isLongData;
110             this.isNull = copyMe.isNull;
111             this.bufferType = copyMe.bufferType;
112             this.bindLength = copyMe.bindLength;
113             this.byteBinding = copyMe.byteBinding;
114             this.shortBinding = copyMe.shortBinding;
115             this.intBinding = copyMe.intBinding;
116             this.longBinding = copyMe.longBinding;
117             this.floatBinding = copyMe.floatBinding;
118             this.doubleBinding = copyMe.doubleBinding;
119         }
120
121         void reset() {
122             this.isSet = false;
123             this.value = null;
124             this.isLongData = false;
125
126             this.byteBinding = 0;
127             this.shortBinding = 0;
128             this.intBinding = 0;
129             this.longBinding = 0L;
130             this.floatBinding = 0;
131             this.doubleBinding = 0D;
132         }
133
134         public String JavaDoc toString() {
135             return toString(false);
136         }
137
138         public String JavaDoc toString(boolean quoteIfNeeded) {
139             if (this.isLongData) {
140                 return "' STREAM DATA '";
141             }
142
143             switch (this.bufferType) {
144             case MysqlDefs.FIELD_TYPE_TINY:
145                 return String.valueOf(byteBinding);
146             case MysqlDefs.FIELD_TYPE_SHORT:
147                 return String.valueOf(shortBinding);
148             case MysqlDefs.FIELD_TYPE_LONG:
149                 return String.valueOf(intBinding);
150             case MysqlDefs.FIELD_TYPE_LONGLONG:
151                 return String.valueOf(longBinding);
152             case MysqlDefs.FIELD_TYPE_FLOAT:
153                 return String.valueOf(floatBinding);
154             case MysqlDefs.FIELD_TYPE_DOUBLE:
155                 return String.valueOf(doubleBinding);
156             case MysqlDefs.FIELD_TYPE_TIME:
157             case MysqlDefs.FIELD_TYPE_DATE:
158             case MysqlDefs.FIELD_TYPE_DATETIME:
159             case MysqlDefs.FIELD_TYPE_TIMESTAMP:
160             case MysqlDefs.FIELD_TYPE_VAR_STRING:
161             case MysqlDefs.FIELD_TYPE_STRING:
162             case MysqlDefs.FIELD_TYPE_VARCHAR:
163                 if (quoteIfNeeded) {
164                     return "'" + String.valueOf(value) + "'";
165                 } else {
166                     return String.valueOf(value);
167                 }
168             default:
169                 if (value instanceof byte[]) {
170                     return "byte data";
171
172                 } else {
173                     if (quoteIfNeeded) {
174                         return "'" + String.valueOf(value) + "'";
175                     } else {
176                         return String.valueOf(value);
177                     }
178                 }
179             }
180         }
181     }
182
183     /* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
184     private static final byte MAX_DATE_REP_LENGTH = (byte) 5;
185
186     /*
187      * 1 (length) + 2 (year) + 1 (month) + 1 (day) + 1 (hour) + 1 (minute) + 1
188      * (second) + 4 (microseconds)
189      */

190     private static final byte MAX_DATETIME_REP_LENGTH = 12;
191
192     /*
193      * 1 (length) + 1 (is negative) + 4 (day count) + 1 (hour) + 1 (minute) + 1
194      * (seconds) + 4 (microseconds)
195      */

196     private static final byte MAX_TIME_REP_LENGTH = 13;
197
198     private static void storeTime(Buffer intoBuf, Time JavaDoc tm) throws SQLException JavaDoc {
199         intoBuf.ensureCapacity(9);
200         intoBuf.writeByte((byte) 8); // length
201
intoBuf.writeByte((byte) 0); // neg flag
202
intoBuf.writeLong(0); // tm->day, not used
203

204         Calendar JavaDoc cal = Calendar.getInstance();
205         cal.setTime(tm);
206         intoBuf.writeByte((byte) cal.get(Calendar.HOUR_OF_DAY));
207         intoBuf.writeByte((byte) cal.get(Calendar.MINUTE));
208         intoBuf.writeByte((byte) cal.get(Calendar.SECOND));
209
210         // intoBuf.writeLongInt(0); // tm-second_part
211
}
212
213     /** The Calendar instance used to create date/time bindings */
214     private Calendar JavaDoc dateTimeBindingCal = null;
215
216     /**
217      * Flag indicating whether or not the long parameters have been 'switched'
218      * back to normal parameters. We can not execute() if clearParameters()
219      * hasn't been called in this case.
220      */

221     private boolean detectedLongParameterSwitch = false;
222
223     /**
224      * The number of fields in the result set (if any) for this
225      * PreparedStatement.
226      */

227     private int fieldCount;
228
229     /** Has this prepared statement been marked invalid? */
230     private boolean invalid = false;
231
232     /** If this statement has been marked invalid, what was the reason? */
233     private SQLException JavaDoc invalidationException;
234
235     /** Does this query modify data? */
236     private boolean isSelectQuery;
237
238     private Buffer outByteBuffer;
239
240     /** Bind values for individual fields */
241     private BindValue[] parameterBindings;
242
243     /** Field-level metadata for parameters */
244     private Field[] parameterFields;
245
246     /** Field-level metadata for result sets. */
247     private Field[] resultFields;
248
249     /** Do we need to send/resend types to the server? */
250     private boolean sendTypesToServer = false;
251
252     /** The ID that the server uses to identify this PreparedStatement */
253     private long serverStatementId;
254
255     /** The type used for string bindings, changes from version-to-version */
256     private int stringTypeCode = MysqlDefs.FIELD_TYPE_STRING;
257
258     private boolean serverNeedsResetBeforeEachExecution;
259
260     /**
261      * Creates a new ServerPreparedStatement object.
262      *
263      * @param conn
264      * the connection creating us.
265      * @param sql
266      * the SQL containing the statement to prepare.
267      * @param catalog
268      * the catalog in use when we were created.
269      *
270      * @throws SQLException
271      * If an error occurs
272      */

273     public ServerPreparedStatement(Connection conn, String JavaDoc sql, String JavaDoc catalog)
274             throws SQLException JavaDoc {
275         super(conn, catalog);
276
277         checkNullOrEmptyQuery(sql);
278
279         this.isSelectQuery = StringUtils.startsWithIgnoreCaseAndWs(sql,
280                 "SELECT"); //$NON-NLS-1$
281

282         if (this.connection.versionMeetsMinimum(5, 0, 0)) {
283             this.serverNeedsResetBeforeEachExecution =
284                 !this.connection.versionMeetsMinimum(5, 0, 3);
285         } else {
286             this.serverNeedsResetBeforeEachExecution =
287                 !this.connection.versionMeetsMinimum(4, 1, 10);
288         }
289         
290         this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
291         this.hasLimitClause = (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1); //$NON-NLS-1$
292
this.firstCharOfStmt = StringUtils.firstNonWsCharUc(sql);
293         this.originalSql = sql;
294
295         if (this.connection.versionMeetsMinimum(4, 1, 2)) {
296             this.stringTypeCode = MysqlDefs.FIELD_TYPE_VAR_STRING;
297         } else {
298             this.stringTypeCode = MysqlDefs.FIELD_TYPE_STRING;
299         }
300
301         try {
302             serverPrepare(sql);
303         } catch (SQLException JavaDoc sqlEx) {
304             realClose(false);
305             // don't wrap SQLExceptions
306
throw sqlEx;
307         } catch (Exception JavaDoc ex) {
308             realClose(false);
309
310             throw new SQLException JavaDoc(ex.toString(),
311                     SQLError.SQL_STATE_GENERAL_ERROR);
312         }
313     }
314
315     /**
316      * JDBC 2.0 Add a set of parameters to the batch.
317      *
318      * @exception SQLException
319      * if a database-access error occurs.
320      *
321      * @see Statement#addBatch
322      */

323     public synchronized void addBatch() throws SQLException JavaDoc {
324         checkClosed();
325
326         if (this.batchedArgs == null) {
327             this.batchedArgs = new ArrayList JavaDoc();
328         }
329
330         this.batchedArgs.add(new BatchedBindValues(this.parameterBindings));
331     }
332
333     protected String JavaDoc asSql(boolean quoteStreamsAndUnknowns) throws SQLException JavaDoc {
334
335         PreparedStatement pStmtForSub = null;
336
337         try {
338             pStmtForSub = new PreparedStatement(this.connection,
339                     this.originalSql, this.currentCatalog);
340
341             int numParameters = pStmtForSub.parameterCount;
342             int ourNumParameters = this.parameterCount;
343
344             for (int i = 0; (i < numParameters) && (i < ourNumParameters); i++) {
345                 if (this.parameterBindings[i] != null) {
346                     if (this.parameterBindings[i].isNull) {
347                         pStmtForSub.setNull(i + 1, Types.NULL);
348                     } else {
349                         BindValue bindValue = this.parameterBindings[i];
350
351                         //
352
// Handle primitives first
353
//
354
switch (bindValue.bufferType) {
355
356                         case MysqlDefs.FIELD_TYPE_TINY:
357                             pStmtForSub.setByte(i + 1, bindValue.byteBinding);
358                             break;
359                         case MysqlDefs.FIELD_TYPE_SHORT:
360                             pStmtForSub.setShort(i + 1, bindValue.shortBinding);
361                             break;
362                         case MysqlDefs.FIELD_TYPE_LONG:
363                             pStmtForSub.setInt(i + 1, bindValue.intBinding);
364                             break;
365                         case MysqlDefs.FIELD_TYPE_LONGLONG:
366                             pStmtForSub.setLong(i + 1, bindValue.longBinding);
367                             break;
368                         case MysqlDefs.FIELD_TYPE_FLOAT:
369                             pStmtForSub.setFloat(i + 1, bindValue.floatBinding);
370                             break;
371                         case MysqlDefs.FIELD_TYPE_DOUBLE:
372                             pStmtForSub.setDouble(i + 1,
373                                     bindValue.doubleBinding);
374                             break;
375                         default:
376                             pStmtForSub.setObject(i + 1,
377                                     this.parameterBindings[i].value);
378                             break;
379                         }
380                     }
381                 }
382             }
383
384             return pStmtForSub.asSql(quoteStreamsAndUnknowns);
385         } finally {
386             if (pStmtForSub != null) {
387                 try {
388                     pStmtForSub.close();
389                 } catch (SQLException JavaDoc sqlEx) {
390                     ; // ignore
391
}
392             }
393         }
394     }
395
396     /*
397      * (non-Javadoc)
398      *
399      * @see com.mysql.jdbc.Statement#checkClosed()
400      */

401     protected void checkClosed() throws SQLException JavaDoc {
402         if (this.invalid) {
403             throw this.invalidationException;
404         }
405
406         //super.checkClosed();
407
}
408
409     /**
410      * @see java.sql.PreparedStatement#clearParameters()
411      */

412     public void clearParameters() throws SQLException JavaDoc {
413         clearParametersInternal(true);
414     }
415
416     private void clearParametersInternal(boolean clearServerParameters)
417             throws SQLException JavaDoc {
418         boolean hadLongData = false;
419
420         if (this.parameterBindings != null) {
421             for (int i = 0; i < this.parameterCount; i++) {
422                 if ((this.parameterBindings[i] != null)
423                         && this.parameterBindings[i].isLongData) {
424                     hadLongData = true;
425                 }
426
427                 this.parameterBindings[i].reset();
428             }
429         }
430
431         if (clearServerParameters && hadLongData) {
432             serverResetStatement();
433
434             this.detectedLongParameterSwitch = false;
435         }
436     }
437
438     protected boolean isCached = false;
439
440     protected void setClosed(boolean flag) {
441         this.isClosed = flag;
442     }
443     /**
444      * @see java.sql.Statement#close()
445      */

446     public void close() throws SQLException JavaDoc {
447         if (this.isCached) {
448             this.isClosed = true;
449             this.connection.recachePreparedStatement(this);
450             return;
451         }
452         
453         realClose(true);
454     }
455
456     private void dumpCloseForTestcase() {
457         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
458         this.connection.generateConnectionCommentBlock(buf);
459         buf.append("DEALLOCATE PREPARE debug_stmt_");
460         buf.append(this.statementId);
461         buf.append(";\n");
462
463         this.connection.dumpTestcaseQuery(buf.toString());
464     }
465
466     private void dumpExecuteForTestcase() throws SQLException JavaDoc {
467         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
468
469         for (int i = 0; i < this.parameterCount; i++) {
470             this.connection.generateConnectionCommentBlock(buf);
471
472             buf.append("SET @debug_stmt_param");
473             buf.append(this.statementId);
474             buf.append("_");
475             buf.append(i);
476             buf.append("=");
477
478             if (this.parameterBindings[i].isNull) {
479                 buf.append("NULL");
480             } else {
481                 buf.append(this.parameterBindings[i].toString(true));
482             }
483
484             buf.append(";\n");
485         }
486
487         this.connection.generateConnectionCommentBlock(buf);
488
489         buf.append("EXECUTE debug_stmt_");
490         buf.append(this.statementId);
491
492         if (this.parameterCount > 0) {
493             buf.append(" USING ");
494             for (int i = 0; i < this.parameterCount; i++) {
495                 if (i > 0) {
496                     buf.append(", ");
497                 }
498
499                 buf.append("@debug_stmt_param");
500                 buf.append(this.serverStatementId);
501                 buf.append("_");
502                 buf.append(i);
503
504             }
505         }
506
507         buf.append(";\n");
508
509         this.connection.dumpTestcaseQuery(buf.toString());
510     }
511
512     private void dumpPrepareForTestcase() throws SQLException JavaDoc {
513
514         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(this.originalSql.length() + 64);
515
516         this.connection.generateConnectionCommentBlock(buf);
517
518         buf.append("PREPARE debug_stmt_");
519         buf.append(this.statementId);
520         buf.append(" FROM \"");
521         buf.append(this.originalSql);
522         buf.append("\";\n");
523
524         this.connection.dumpTestcaseQuery(buf.toString());
525     }
526
527     /**
528      * @see java.sql.Statement#executeBatch()
529      */

530     public synchronized int[] executeBatch() throws SQLException JavaDoc {
531         if (this.connection.isReadOnly()) {
532             throw new SQLException JavaDoc(Messages
533                     .getString("ServerPreparedStatement.2") //$NON-NLS-1$
534
+ Messages.getString("ServerPreparedStatement.3"), //$NON-NLS-1$
535
SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
536         }
537
538         checkClosed();
539
540         synchronized (this.connection.getMutex()) {
541             clearWarnings();
542
543             // Store this for later, we're going to 'swap' them out
544
// as we execute each batched statement...
545
BindValue[] oldBindValues = this.parameterBindings;
546
547             try {
548                 int[] updateCounts = null;
549
550                 if (this.batchedArgs != null) {
551                     int nbrCommands = this.batchedArgs.size();
552                     updateCounts = new int[nbrCommands];
553
554                     if (this.retrieveGeneratedKeys) {
555                         this.batchedGeneratedKeys = new ArrayList JavaDoc(nbrCommands);
556                     }
557
558                     for (int i = 0; i < nbrCommands; i++) {
559                         updateCounts[i] = -3;
560                     }
561
562                     SQLException JavaDoc sqlEx = null;
563
564                     int commandIndex = 0;
565
566                     BindValue[] previousBindValuesForBatch = null;
567
568                     for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
569                         Object JavaDoc arg = this.batchedArgs.get(commandIndex);
570
571                         if (arg instanceof String JavaDoc) {
572                             updateCounts[commandIndex] = executeUpdate((String JavaDoc) arg);
573                         } else {
574                             this.parameterBindings = ((BatchedBindValues) arg).batchedParameterValues;
575
576                             try {
577                                 // We need to check types each time, as
578
// the user might have bound different
579
// types in each addBatch()
580

581                                 if (previousBindValuesForBatch != null) {
582                                     for (int j = 0; j < this.parameterBindings.length; j++) {
583                                         if (this.parameterBindings[j].bufferType != previousBindValuesForBatch[j].bufferType) {
584                                             this.sendTypesToServer = true;
585
586                                             break;
587                                         }
588                                     }
589                                 }
590
591                                 try {
592                                     updateCounts[commandIndex] = executeUpdate(false);
593                                 } finally {
594                                     previousBindValuesForBatch = this.parameterBindings;
595                                 }
596
597                                 if (this.retrieveGeneratedKeys) {
598                                     java.sql.ResultSet JavaDoc rs = null;
599
600                                     try {
601                                         // we don't want to use our version,
602
// because we've altered the behavior of
603
// ours to support batch updates
604
// (catch-22)
605
// Ideally, what we need here is
606
// super.super.getGeneratedKeys()
607
// but that construct doesn't exist in
608
// Java, so that's why there's
609
// this kludge.
610
rs = getGeneratedKeysInternal();
611
612                                         while (rs.next()) {
613                                             this.batchedGeneratedKeys
614                                                     .add(new byte[][] { rs
615                                                             .getBytes(1) });
616                                         }
617                                     } finally {
618                                         if (rs != null) {
619                                             rs.close();
620                                         }
621                                     }
622                                 }
623                             } catch (SQLException JavaDoc ex) {
624                                 updateCounts[commandIndex] = EXECUTE_FAILED;
625
626                                 if (this.connection.getContinueBatchOnError()) {
627                                     sqlEx = ex;
628                                 } else {
629                                     int[] newUpdateCounts = new int[commandIndex];
630                                     System.arraycopy(updateCounts, 0,
631                                             newUpdateCounts, 0, commandIndex);
632
633                                     throw new java.sql.BatchUpdateException JavaDoc(ex
634                                             .getMessage(), ex.getSQLState(), ex
635                                             .getErrorCode(), newUpdateCounts);
636                                 }
637                             }
638                         }
639                     }
640
641                     if (sqlEx != null) {
642                         throw new java.sql.BatchUpdateException JavaDoc(sqlEx
643                                 .getMessage(), sqlEx.getSQLState(), sqlEx
644                                 .getErrorCode(), updateCounts);
645                     }
646                 }
647
648                 return (updateCounts != null) ? updateCounts : new int[0];
649             } finally {
650                 this.parameterBindings = oldBindValues;
651                 this.sendTypesToServer = true;
652
653                 clearBatch();
654             }
655         }
656     }
657
658     /**
659      * @see com.mysql.jdbc.PreparedStatement#executeInternal(int,
660      * com.mysql.jdbc.Buffer, boolean, boolean)
661      */

662     protected com.mysql.jdbc.ResultSet executeInternal(int maxRowsToRetrieve,
663             Buffer sendPacket, boolean createStreamingResultSet,
664             boolean queryIsSelectOnly, boolean unpackFields)
665             throws SQLException JavaDoc {
666         this.numberOfExecutions++;
667
668         // We defer to server-side execution
669
try {
670             return serverExecute(maxRowsToRetrieve, createStreamingResultSet);
671         } catch (SQLException JavaDoc sqlEx) {
672             // don't wrap SQLExceptions
673
if (this.connection.getEnablePacketDebug()) {
674                 this.connection.getIO().dumpPacketRingBuffer();
675             }
676
677             if (this.connection.getDumpQueriesOnException()) {
678                 String JavaDoc extractedSql = toString();
679                 StringBuffer JavaDoc messageBuf = new StringBuffer JavaDoc(extractedSql
680                         .length() + 32);
681                 messageBuf
682                         .append("\n\nQuery being executed when exception was thrown:\n\n");
683                 messageBuf.append(extractedSql);
684
685                 sqlEx = Connection.appendMessageToException(sqlEx, messageBuf
686                         .toString());
687             }
688
689             throw sqlEx;
690         } catch (Exception JavaDoc ex) {
691             if (this.connection.getEnablePacketDebug()) {
692                 this.connection.getIO().dumpPacketRingBuffer();
693             }
694
695             SQLException JavaDoc sqlEx = new SQLException JavaDoc(ex.toString(),
696                     SQLError.SQL_STATE_GENERAL_ERROR);
697
698             if (this.connection.getDumpQueriesOnException()) {
699                 String JavaDoc extractedSql = toString();
700                 StringBuffer JavaDoc messageBuf = new StringBuffer JavaDoc(extractedSql
701                         .length() + 32);
702                 messageBuf
703                         .append("\n\nQuery being executed when exception was thrown:\n\n");
704                 messageBuf.append(extractedSql);
705
706                 sqlEx = Connection.appendMessageToException(sqlEx, messageBuf
707                         .toString());
708             }
709
710             throw sqlEx;
711         }
712     }
713
714     /**
715      * @see com.mysql.jdbc.PreparedStatement#fillSendPacket()
716      */

717     protected Buffer fillSendPacket() throws SQLException JavaDoc {
718         return null; // we don't use this type of packet
719
}
720
721     /**
722      * @see com.mysql.jdbc.PreparedStatement#fillSendPacket(byte,
723      * java.io.InputStream, boolean, int)
724      */

725     protected Buffer fillSendPacket(byte[][] batchedParameterStrings,
726             InputStream JavaDoc[] batchedParameterStreams, boolean[] batchedIsStream,
727             int[] batchedStreamLengths) throws SQLException JavaDoc {
728         return null; // we don't use this type of packet
729
}
730
731     private BindValue getBinding(int parameterIndex, boolean forLongData)
732             throws SQLException JavaDoc {
733         if (this.parameterBindings.length == 0) {
734             throw new SQLException JavaDoc(Messages
735                     .getString("ServerPreparedStatement.8"), //$NON-NLS-1$
736
SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
737         }
738
739         parameterIndex--;
740
741         if ((parameterIndex < 0)
742                 || (parameterIndex >= this.parameterBindings.length)) {
743             throw new SQLException JavaDoc(Messages
744                     .getString("ServerPreparedStatement.9") //$NON-NLS-1$
745
+ (parameterIndex + 1)
746                     + Messages.getString("ServerPreparedStatement.10") //$NON-NLS-1$
747
+ this.parameterBindings.length,
748                     SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
749         }
750
751         if (this.parameterBindings[parameterIndex] == null) {
752             this.parameterBindings[parameterIndex] = new BindValue();
753         } else {
754             if (this.parameterBindings[parameterIndex].isLongData
755                     && !forLongData) {
756                 this.detectedLongParameterSwitch = true;
757             }
758         }
759
760         this.parameterBindings[parameterIndex].isSet = true;
761
762         return this.parameterBindings[parameterIndex];
763     }
764
765     /**
766      * @see com.mysql.jdbc.PreparedStatement#getBytes(int)
767      */

768     synchronized byte[] getBytes(int parameterIndex) throws SQLException JavaDoc {
769         BindValue bindValue = getBinding(parameterIndex, false);
770
771         if (bindValue.isNull) {
772             return null;
773         } else if (bindValue.isLongData) {
774             throw new NotImplemented();
775         } else {
776             if (this.outByteBuffer == null) {
777                 this.outByteBuffer = Buffer.allocateNew(this.connection
778                         .getNetBufferLength(), false);
779             }
780
781             this.outByteBuffer.clear();
782
783             int originalPosition = this.outByteBuffer.getPosition();
784
785             storeBinding(this.outByteBuffer, bindValue, this.connection.getIO());
786
787             int newPosition = this.outByteBuffer.getPosition();
788
789             int length = newPosition - originalPosition;
790
791             byte[] valueAsBytes = new byte[length];
792
793             System.arraycopy(this.outByteBuffer.getByteBuffer(),
794                     originalPosition, valueAsBytes, 0, length);
795
796             return valueAsBytes;
797         }
798     }
799
800     /**
801      * @see java.sql.PreparedStatement#getMetaData()
802      */

803     public java.sql.ResultSetMetaData JavaDoc getMetaData() throws SQLException JavaDoc {
804         checkClosed();
805
806         if (this.resultFields == null) {
807             return null;
808         }
809
810         return new ResultSetMetaData(this.resultFields);
811     }
812
813     /**
814      * @see java.sql.PreparedStatement#getParameterMetaData()
815      */

816     public synchronized ParameterMetaData JavaDoc getParameterMetaData() throws SQLException JavaDoc {
817         checkClosed();
818         
819         if (this.parameterMetaData == null) {
820             this.parameterMetaData = new MysqlParameterMetadata(
821                     this.parameterFields, this.parameterCount);
822         }
823         
824         return this.parameterMetaData;
825     }
826
827     /**
828      * @see com.mysql.jdbc.PreparedStatement#isNull(int)
829      */

830     boolean isNull(int paramIndex) {
831         throw new IllegalArgumentException JavaDoc(Messages
832                 .getString("ServerPreparedStatement.7")); //$NON-NLS-1$
833
}
834
835     /**
836      * Closes this connection and frees all resources.
837      *
838      * @param calledExplicitly
839      * was this called from close()?
840      *
841      * @throws SQLException
842      * if an error occurs
843      */

844     protected void realClose(boolean calledExplicitly) throws SQLException JavaDoc {
845         if (this.isClosed) {
846             return;
847         }
848
849         if (this.connection != null &&
850                 this.connection.getAutoGenerateTestcaseScript()) {
851             dumpCloseForTestcase();
852         }
853
854         //
855
// Don't communicate with the server if we're being
856
// called from the finalizer...
857
//
858
// This will leak server resources, but if we don't do this,
859
// we'll deadlock (potentially, because there's no guarantee
860
// when, what order, and what concurrency finalizers will be
861
// called with). Well-behaved programs won't rely on finalizers
862
// to clean up their statements.
863
//
864

865         SQLException JavaDoc exceptionDuringClose = null;
866
867         if (calledExplicitly) {
868             try {
869                 synchronized (this.connection.getMutex()) {
870                     MysqlIO mysql = this.connection.getIO();
871
872                     Buffer packet = mysql.getSharedSendPacket();
873
874                     packet.writeByte((byte) MysqlDefs.COM_CLOSE_STATEMENT);
875                     packet.writeLong(this.serverStatementId);
876
877                     mysql.sendCommand(MysqlDefs.COM_CLOSE_STATEMENT, null,
878                             packet, true, null);
879                 }
880             } catch (SQLException JavaDoc sqlEx) {
881                 exceptionDuringClose = sqlEx;
882             }
883         }
884
885         clearParametersInternal(false);
886         this.parameterBindings = null;
887
888         this.parameterFields = null;
889         this.resultFields = null;
890
891         super.realClose(calledExplicitly);
892
893         if (exceptionDuringClose != null) {
894             throw exceptionDuringClose;
895         }
896     }
897
898     /**
899      * Used by Connection when auto-reconnecting to retrieve 'lost' prepared
900      * statements.
901      *
902      * @throws SQLException
903      * if an error occurs.
904      */

905     protected void rePrepare() throws SQLException JavaDoc {
906         this.invalidationException = null;
907
908         try {
909             serverPrepare(this.originalSql);
910         } catch (SQLException JavaDoc sqlEx) {
911             // don't wrap SQLExceptions
912
this.invalidationException = sqlEx;
913         } catch (Exception JavaDoc ex) {
914             this.invalidationException = new SQLException JavaDoc(ex.toString(),
915                     SQLError.SQL_STATE_GENERAL_ERROR);
916         }
917
918         if (this.invalidationException != null) {
919             this.invalid = true;
920
921             this.parameterBindings = null;
922
923             this.parameterFields = null;
924             this.resultFields = null;
925
926             if (this.results != null) {
927                 try {
928                     this.results.close();
929                 } catch (Exception JavaDoc ex) {
930                     ;
931                 }
932             }
933
934             if (this.connection != null) {
935                 if (this.maxRowsChanged) {
936                     this.connection.unsetMaxRows(this);
937                 }
938
939                 if (!this.connection.getDontTrackOpenResources()) {
940                     this.connection.unregisterStatement(this);
941                 }
942             }
943         }
944     }
945
946     /**
947      * Tells the server to execute this prepared statement with the current
948      * parameter bindings.
949      *
950      * <pre>
951      *
952      *
953      * - Server gets the command 'COM_EXECUTE' to execute the
954      * previously prepared query. If there is any param markers;
955      * then client will send the data in the following format:
956      *
957      * [COM_EXECUTE:1]
958      * [STMT_ID:4]
959      * [NULL_BITS:(param_count+7)/8)]
960      * [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
961      * [[length]data]
962      * [[length]data] .. [[length]data].
963      *
964      * (Note: Except for string/binary types; all other types will not be
965      * supplied with length field)
966      *
967      *
968      * </pre>
969      *
970      * @param maxRowsToRetrieve
971      * DOCUMENT ME!
972      * @param createStreamingResultSet
973      * DOCUMENT ME!
974      *
975      * @return DOCUMENT ME!
976      *
977      * @throws SQLException
978      */

979     private com.mysql.jdbc.ResultSet serverExecute(int maxRowsToRetrieve,
980             boolean createStreamingResultSet) throws SQLException JavaDoc {
981         synchronized (this.connection.getMutex()) {
982             if (this.detectedLongParameterSwitch) {
983                 throw new SQLException JavaDoc(Messages
984                         .getString("ServerPreparedStatement.11") //$NON-NLS-1$
985
+ Messages.getString("ServerPreparedStatement.12"), //$NON-NLS-1$
986
SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
987             }
988
989             // Check bindings
990
for (int i = 0; i < this.parameterCount; i++) {
991                 if (!this.parameterBindings[i].isSet) {
992                     throw new SQLException JavaDoc(Messages
993                             .getString("ServerPreparedStatement.13") + (i + 1) //$NON-NLS-1$
994
+ Messages.getString("ServerPreparedStatement.14"),
995                             SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
996
}
997             }
998
999             //
1000
// Send all long data
1001
//
1002
for (int i = 0; i < this.parameterCount; i++) {
1003                if (this.parameterBindings[i].isLongData) {
1004                    serverLongData(i, this.parameterBindings[i]);
1005                }
1006            }
1007
1008            if (this.connection.getAutoGenerateTestcaseScript()) {
1009                dumpExecuteForTestcase();
1010            }
1011
1012            //
1013
// store the parameter values
1014
//
1015
MysqlIO mysql = this.connection.getIO();
1016
1017            Buffer packet = mysql.getSharedSendPacket();
1018
1019            packet.clear();
1020            packet.writeByte((byte) MysqlDefs.COM_EXECUTE);
1021            packet.writeLong(this.serverStatementId);
1022
1023            if (this.connection.versionMeetsMinimum(4, 1, 2)) {
1024                packet.writeByte((byte) 0); // placeholder for flags
1025
packet.writeLong(1); // placeholder for parameter iterations
1026
}
1027
1028            /* Reserve place for null-marker bytes */
1029            int nullCount = (this.parameterCount + 7) / 8;
1030
1031            // if (mysql.versionMeetsMinimum(4, 1, 2)) {
1032
// nullCount = (this.parameterCount + 9) / 8;
1033
// }
1034
int nullBitsPosition = packet.getPosition();
1035
1036            for (int i = 0; i < nullCount; i++) {
1037                packet.writeByte((byte) 0);
1038            }
1039
1040            byte[] nullBitsBuffer = new byte[nullCount];
1041
1042            /* In case if buffers (type) altered, indicate to server */
1043            packet.writeByte(this.sendTypesToServer ? (byte) 1 : (byte) 0);
1044
1045            if (this.sendTypesToServer) {
1046                /*
1047                 * Store types of parameters in first in first package that is
1048                 * sent to the server.
1049                 */

1050                for (int i = 0; i < this.parameterCount; i++) {
1051                    packet.writeInt(this.parameterBindings[i].bufferType);
1052                }
1053            }
1054
1055            //
1056
// store the parameter values
1057
//
1058
for (int i = 0; i < this.parameterCount; i++) {
1059                if (!this.parameterBindings[i].isLongData) {
1060                    if (!this.parameterBindings[i].isNull) {
1061                        storeBinding(packet, this.parameterBindings[i], mysql);
1062                    } else {
1063                        nullBitsBuffer[i / 8] |= (1 << (i & 7));
1064                    }
1065                }
1066            }
1067
1068            //
1069
// Go back and write the NULL flags
1070
// to the beginning of the packet
1071
//
1072
int endPosition = packet.getPosition();
1073            packet.setPosition(nullBitsPosition);
1074            packet.writeBytesNoNull(nullBitsBuffer);
1075            packet.setPosition(endPosition);
1076
1077            long begin = 0;
1078
1079            if (this.connection.getProfileSql()
1080                    || this.connection.getLogSlowQueries()
1081                    || this.connection.getGatherPerformanceMetrics()) {
1082                begin = System.currentTimeMillis();
1083            }
1084
1085            Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE,
1086                    null, packet, false, null);
1087
1088            if (this.connection.getLogSlowQueries()
1089                    || this.connection.getGatherPerformanceMetrics()) {
1090                long elapsedTime = System.currentTimeMillis() - begin;
1091
1092                if (this.connection.getLogSlowQueries()
1093                        && (elapsedTime > this.connection
1094                                .getSlowQueryThresholdMillis())) {
1095                    StringBuffer JavaDoc mesgBuf = new StringBuffer JavaDoc(
1096                            48 + this.originalSql.length());
1097                    mesgBuf.append(Messages
1098                            .getString("ServerPreparedStatement.15")); //$NON-NLS-1$
1099
mesgBuf.append(this.connection
1100                            .getSlowQueryThresholdMillis());
1101                    mesgBuf.append(Messages
1102                            .getString("ServerPreparedStatement.16")); //$NON-NLS-1$
1103
mesgBuf.append(this.originalSql);
1104
1105                    this.connection.getLog().logWarn(mesgBuf.toString());
1106
1107                    if (this.connection.getExplainSlowQueries()) {
1108                        String JavaDoc queryAsString = asSql(true);
1109
1110                        mysql.explainSlowQuery(queryAsString.getBytes(),
1111                                queryAsString);
1112                    }
1113                }
1114
1115                if (this.connection.getGatherPerformanceMetrics()) {
1116                    this.connection.registerQueryExecutionTime(elapsedTime);
1117                }
1118            }
1119
1120            this.connection.incrementNumberOfPreparedExecutes();
1121
1122            if (this.connection.getProfileSql()) {
1123                this.eventSink = ProfileEventSink.getInstance(this.connection);
1124
1125                this.eventSink.consumeEvent(new ProfilerEvent(
1126                        ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$
1127
this.connection.getId(), this.statementId, -1, System
1128                                .currentTimeMillis(), (int) (System
1129                                .currentTimeMillis() - begin), null,
1130                        new Throwable JavaDoc(), null));
1131            }
1132
1133            com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this,
1134                    maxRowsToRetrieve, this.resultSetType,
1135                    this.resultSetConcurrency, createStreamingResultSet,
1136                    this.currentCatalog, resultPacket, true, this.fieldCount,
1137                    true);
1138
1139            
1140            if (!createStreamingResultSet &&
1141                    this.serverNeedsResetBeforeEachExecution) {
1142                serverResetStatement(); // clear any long data...
1143
}
1144
1145            this.sendTypesToServer = false;
1146            this.results = rs;
1147
1148            return rs;
1149        }
1150    }
1151
1152    /**
1153     * Sends stream-type data parameters to the server.
1154     *
1155     * <pre>
1156     *
1157     * Long data handling:
1158     *
1159     * - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
1160     * - The packet recieved will have the format as:
1161     * [COM_LONG_DATA: 1][STMT_ID:4][parameter_number:2][type:2][data]
1162     * - Checks if the type is specified by client, and if yes reads the type,
1163     * and stores the data in that format.
1164     * - It's up to the client to check for read data ended. The server doesn't
1165     * care; and also server doesn't notify to the client that it got the
1166     * data or not; if there is any error; then during execute; the error
1167     * will be returned
1168     *
1169     * </pre>
1170     *
1171     * @param parameterIndex
1172     * DOCUMENT ME!
1173     * @param longData
1174     * DOCUMENT ME!
1175     *
1176     * @throws SQLException
1177     * if an error occurs.
1178     */

1179    private void serverLongData(int parameterIndex, BindValue longData)
1180            throws SQLException JavaDoc {
1181        synchronized (this.connection.getMutex()) {
1182            MysqlIO mysql = this.connection.getIO();
1183
1184            Buffer packet = mysql.getSharedSendPacket();
1185
1186            Object JavaDoc value = longData.value;
1187
1188            if (value instanceof byte[]) {
1189                packet.clear();
1190                packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
1191                packet.writeLong(this.serverStatementId);
1192                packet.writeInt((parameterIndex));
1193
1194                packet.writeBytesNoNull((byte[]) longData.value);
1195
1196                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
1197                        null);
1198            } else if (value instanceof InputStream JavaDoc) {
1199                storeStream(mysql, parameterIndex, packet, (InputStream JavaDoc) value);
1200            } else if (value instanceof java.sql.Blob JavaDoc) {
1201                storeStream(mysql, parameterIndex, packet,
1202                        ((java.sql.Blob JavaDoc) value).getBinaryStream());
1203            } else if (value instanceof Reader JavaDoc) {
1204                storeReader(mysql, parameterIndex, packet, (Reader JavaDoc) value);
1205            } else {
1206                throw new SQLException JavaDoc(Messages
1207                        .getString("ServerPreparedStatement.18") //$NON-NLS-1$
1208
+ value.getClass().getName() + "'", //$NON-NLS-1$
1209
SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1210            }
1211        }
1212    }
1213
1214    private void serverPrepare(String JavaDoc sql) throws SQLException JavaDoc {
1215        synchronized (this.connection.getMutex()) {
1216            MysqlIO mysql = this.connection.getIO();
1217
1218            if (this.connection.getAutoGenerateTestcaseScript()) {
1219                dumpPrepareForTestcase();
1220            }
1221
1222            try {
1223                long begin = 0;
1224
1225                if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) { //$NON-NLS-1$
1226
this.isLoadDataQuery = true;
1227                } else {
1228                    this.isLoadDataQuery = false;
1229                }
1230
1231                if (this.connection.getProfileSql()) {
1232                    begin = System.currentTimeMillis();
1233                }
1234
1235                String JavaDoc characterEncoding = null;
1236                String JavaDoc connectionEncoding = this.connection.getEncoding();
1237
1238                if (!this.isLoadDataQuery && this.connection.getUseUnicode()
1239                        && (connectionEncoding != null)) {
1240                    characterEncoding = connectionEncoding;
1241                }
1242
1243                Buffer prepareResultPacket = mysql.sendCommand(
1244                        MysqlDefs.COM_PREPARE, sql, null, false,
1245                        characterEncoding);
1246
1247                if (this.connection.versionMeetsMinimum(4, 1, 1)) {
1248                    // 4.1.1 and newer use the first byte
1249
// as an 'ok' or 'error' flag, so move
1250
// the buffer pointer past it to
1251
// start reading the statement id.
1252
prepareResultPacket.setPosition(1);
1253                } else {
1254                    // 4.1.0 doesn't use the first byte as an
1255
// 'ok' or 'error' flag
1256
prepareResultPacket.setPosition(0);
1257                }
1258
1259                this.serverStatementId = prepareResultPacket.readLong();
1260                this.fieldCount = prepareResultPacket.readInt();
1261                this.parameterCount = prepareResultPacket.readInt();
1262                this.parameterBindings = new BindValue[this.parameterCount];
1263
1264                for (int i = 0; i < this.parameterCount; i++) {
1265                    this.parameterBindings[i] = new BindValue();
1266                }
1267
1268                this.connection.incrementNumberOfPrepares();
1269
1270                if (this.connection.getProfileSql()) {
1271                    this.eventSink = ProfileEventSink
1272                            .getInstance(this.connection);
1273
1274                    this.eventSink.consumeEvent(new ProfilerEvent(
1275                            ProfilerEvent.TYPE_PREPARE,
1276                            "", this.currentCatalog, //$NON-NLS-1$
1277
this.connection.getId(), this.statementId, -1,
1278                            System.currentTimeMillis(), (int) (System
1279                                    .currentTimeMillis() - begin), null,
1280                            new Throwable JavaDoc(), sql));
1281                }
1282
1283                if (this.parameterCount > 0) {
1284                    if (this.connection.versionMeetsMinimum(4, 1, 2)
1285                            && !mysql.isVersion(5, 0, 0)) {
1286                        this.parameterFields = new Field[this.parameterCount];
1287
1288                        Buffer metaDataPacket = mysql.readPacket();
1289
1290                        int i = 0;
1291
1292                        while (!metaDataPacket.isLastDataPacket()
1293                                && (i < this.parameterCount)) {
1294                            this.parameterFields[i++] = mysql.unpackField(
1295                                    metaDataPacket, false);
1296                            metaDataPacket = mysql.readPacket();
1297                        }
1298                    }
1299                }
1300
1301                if (this.fieldCount > 0) {
1302                    this.resultFields = new Field[this.fieldCount];
1303
1304                    Buffer fieldPacket = mysql.readPacket();
1305
1306                    int i = 0;
1307
1308                    // Read in the result set column information
1309
while (!fieldPacket.isLastDataPacket()
1310                            && (i < this.fieldCount)) {
1311                        this.resultFields[i++] = mysql.unpackField(fieldPacket,
1312                                false);
1313                        fieldPacket = mysql.readPacket();
1314                    }
1315                }
1316            } catch (SQLException JavaDoc sqlEx) {
1317                if (this.connection.getDumpQueriesOnException()) {
1318                    StringBuffer JavaDoc messageBuf = new StringBuffer JavaDoc(this.originalSql
1319                            .length() + 32);
1320                    messageBuf
1321                            .append("\n\nQuery being prepared when exception was thrown:\n\n");
1322                    messageBuf.append(this.originalSql);
1323
1324                    sqlEx = Connection.appendMessageToException(sqlEx,
1325                            messageBuf.toString());
1326                }
1327
1328                throw sqlEx;
1329            } finally {
1330                // Leave the I/O channel in a known state...there might be
1331
// packets out there
1332
// that we're not interested in
1333
this.connection.getIO().clearInputStream();
1334            }
1335        }
1336    }
1337
1338    private void serverResetStatement() throws SQLException JavaDoc {
1339        synchronized (this.connection.getMutex()) {
1340
1341            MysqlIO mysql = this.connection.getIO();
1342
1343            Buffer packet = mysql.getSharedSendPacket();
1344
1345            packet.clear();
1346            packet.writeByte((byte) MysqlDefs.COM_RESET_STMT);
1347            packet.writeLong(this.serverStatementId);
1348
1349            try {
1350                mysql.sendCommand(MysqlDefs.COM_RESET_STMT, null, packet,
1351                        !this.connection.versionMeetsMinimum(4, 1, 2), null);
1352            } catch (SQLException JavaDoc sqlEx) {
1353                throw sqlEx;
1354            } catch (Exception JavaDoc ex) {
1355                throw new SQLException JavaDoc(ex.toString(),
1356                        SQLError.SQL_STATE_GENERAL_ERROR);
1357            } finally {
1358                mysql.clearInputStream();
1359            }
1360        }
1361    }
1362
1363    /**
1364     * @see java.sql.PreparedStatement#setArray(int, java.sql.Array)
1365     */

1366    public void setArray(int i, Array JavaDoc x) throws SQLException JavaDoc {
1367        throw new NotImplemented();
1368    }
1369
1370    /**
1371     * @see java.sql.PreparedStatement#setAsciiStream(int, java.io.InputStream,
1372     * int)
1373     */

1374    public void setAsciiStream(int parameterIndex, InputStream JavaDoc x, int length)
1375            throws SQLException JavaDoc {
1376        checkClosed();
1377
1378        if (x == null) {
1379            setNull(parameterIndex, java.sql.Types.BINARY);
1380        } else {
1381            BindValue binding = getBinding(parameterIndex, true);
1382            setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1383
1384            binding.value = x;
1385            binding.isNull = false;
1386            binding.isLongData = true;
1387
1388            if (this.connection.getUseStreamLengthsInPrepStmts()) {
1389                binding.bindLength = length;
1390            } else {
1391                binding.bindLength = -1;
1392            }
1393        }
1394    }
1395
1396    /**
1397     * @see java.sql.PreparedStatement#setBigDecimal(int, java.math.BigDecimal)
1398     */

1399    public void setBigDecimal(int parameterIndex, BigDecimal JavaDoc x)
1400            throws SQLException JavaDoc {
1401        checkClosed();
1402
1403        if (x == null) {
1404            setNull(parameterIndex, java.sql.Types.DECIMAL);
1405        } else {
1406            setString(parameterIndex, StringUtils.fixDecimalExponent(x
1407                    .toString()));
1408        }
1409    }
1410
1411    /**
1412     * @see java.sql.PreparedStatement#setBinaryStream(int, java.io.InputStream,
1413     * int)
1414     */

1415    public void setBinaryStream(int parameterIndex, InputStream JavaDoc x, int length)
1416            throws SQLException JavaDoc {
1417        checkClosed();
1418
1419        if (x == null) {
1420            setNull(parameterIndex, java.sql.Types.BINARY);
1421        } else {
1422            BindValue binding = getBinding(parameterIndex, true);
1423            setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1424
1425            binding.value = x;
1426            binding.isNull = false;
1427            binding.isLongData = true;
1428
1429            if (this.connection.getUseStreamLengthsInPrepStmts()) {
1430                binding.bindLength = length;
1431            } else {
1432                binding.bindLength = -1;
1433            }
1434        }
1435    }
1436
1437    /**
1438     * @see java.sql.PreparedStatement#setBlob(int, java.sql.Blob)
1439     */

1440    public void setBlob(int parameterIndex, Blob x) throws SQLException JavaDoc {
1441        checkClosed();
1442
1443        if (x == null) {
1444            setNull(parameterIndex, java.sql.Types.BINARY);
1445        } else {
1446            BindValue binding = getBinding(parameterIndex, true);
1447            setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1448
1449            binding.value = x;
1450            binding.isNull = false;
1451            binding.isLongData = true;
1452
1453            if (this.connection.getUseStreamLengthsInPrepStmts()) {
1454                binding.bindLength = x.length();
1455            } else {
1456                binding.bindLength = -1;
1457            }
1458        }
1459    }
1460
1461    /**
1462     * @see java.sql.PreparedStatement#setBoolean(int, boolean)
1463     */

1464    public void setBoolean(int parameterIndex, boolean x) throws SQLException JavaDoc {
1465        setByte(parameterIndex, (x ? (byte) 1 : (byte) 0));
1466    }
1467
1468    /**
1469     * @see java.sql.PreparedStatement#setByte(int, byte)
1470     */

1471    public void setByte(int parameterIndex, byte x) throws SQLException JavaDoc {
1472        checkClosed();
1473
1474        BindValue binding = getBinding(parameterIndex, false);
1475        setType(binding, MysqlDefs.FIELD_TYPE_TINY);
1476
1477        binding.value = null;
1478        binding.byteBinding = x;
1479        binding.isNull = false;
1480        binding.isLongData = false;
1481    }
1482
1483    /**
1484     * @see java.sql.PreparedStatement#setBytes(int, byte)
1485     */

1486    public void setBytes(int parameterIndex, byte[] x) throws SQLException JavaDoc {
1487        checkClosed();
1488
1489        if (x == null) {
1490            setNull(parameterIndex, java.sql.Types.BINARY);
1491        } else {
1492            BindValue binding = getBinding(parameterIndex, false);
1493            setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1494
1495            binding.value = x;
1496            binding.isNull = false;
1497            binding.isLongData = false;
1498        }
1499    }
1500
1501    /**
1502     * @see java.sql.PreparedStatement#setCharacterStream(int, java.io.Reader,
1503     * int)
1504     */

1505    public void setCharacterStream(int parameterIndex, Reader JavaDoc reader, int length)
1506            throws SQLException JavaDoc {
1507        checkClosed();
1508
1509        if (reader == null) {
1510            setNull(parameterIndex, java.sql.Types.BINARY);
1511        } else {
1512            BindValue binding = getBinding(parameterIndex, true);
1513            setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1514
1515            binding.value = reader;
1516            binding.isNull = false;
1517            binding.isLongData = true;
1518
1519            if (this.connection.getUseStreamLengthsInPrepStmts()) {
1520                binding.bindLength = length;
1521            } else {
1522                binding.bindLength = -1;
1523            }
1524        }
1525    }
1526
1527    /**
1528     * @see java.sql.PreparedStatement#setClob(int, java.sql.Clob)
1529     */

1530    public void setClob(int parameterIndex, Clob x) throws SQLException JavaDoc {
1531        checkClosed();
1532
1533        if (x == null) {
1534            setNull(parameterIndex, java.sql.Types.BINARY);
1535        } else {
1536            BindValue binding = getBinding(parameterIndex, true);
1537            setType(binding, MysqlDefs.FIELD_TYPE_BLOB);
1538
1539            binding.value = x.getCharacterStream();
1540            binding.isNull = false;
1541            binding.isLongData = true;
1542
1543            if (this.connection.getUseStreamLengthsInPrepStmts()) {
1544                binding.bindLength = x.length();
1545            } else {
1546                binding.bindLength = -1;
1547            }
1548        }
1549    }
1550
1551    /**
1552     * Set a parameter to a java.sql.Date value. The driver converts this to a
1553     * SQL DATE value when it sends it to the database.
1554     *
1555     * @param parameterIndex
1556     * the first parameter is 1, the second is 2, ...
1557     * @param x
1558     * the parameter value
1559     *
1560     * @exception SQLException
1561     * if a database-access error occurs.
1562     */

1563    public void setDate(int parameterIndex, Date JavaDoc x) throws SQLException JavaDoc {
1564        setDate(parameterIndex, x, null);
1565    }
1566
1567    /**
1568     * Set a parameter to a java.sql.Date value. The driver converts this to a
1569     * SQL DATE value when it sends it to the database.
1570     *
1571     * @param parameterIndex
1572     * the first parameter is 1, the second is 2, ...
1573     * @param x
1574     * the parameter value
1575     * @param cal
1576     * the calendar to interpret the date with
1577     *
1578     * @exception SQLException
1579     * if a database-access error occurs.
1580     */

1581    public void setDate(int parameterIndex, Date JavaDoc x, Calendar JavaDoc cal)
1582            throws SQLException JavaDoc {
1583        if (x == null) {
1584            setNull(parameterIndex, java.sql.Types.DATE);
1585        } else {
1586            BindValue binding = getBinding(parameterIndex, false);
1587            setType(binding, MysqlDefs.FIELD_TYPE_DATE);
1588
1589            binding.value = x;
1590            binding.isNull = false;
1591            binding.isLongData = false;
1592        }
1593    }
1594
1595    /**
1596     * @see java.sql.PreparedStatement#setDouble(int, double)
1597     */

1598    public void setDouble(int parameterIndex, double x) throws SQLException JavaDoc {
1599        checkClosed();
1600
1601        if (!this.connection.getAllowNanAndInf()
1602                && (x == Double.POSITIVE_INFINITY
1603                        || x == Double.NEGATIVE_INFINITY || Double.isNaN(x))) {
1604            throw new SQLException JavaDoc("'" + x
1605                    + "' is not a valid numeric or approximate numeric value",
1606                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1607
1608        }
1609
1610        BindValue binding = getBinding(parameterIndex, false);
1611        setType(binding, MysqlDefs.FIELD_TYPE_DOUBLE);
1612
1613        binding.value = null;
1614        binding.doubleBinding = x;
1615        binding.isNull = false;
1616        binding.isLongData = false;
1617    }
1618
1619    /**
1620     * @see java.sql.PreparedStatement#setFloat(int, float)
1621     */

1622    public void setFloat(int parameterIndex, float x) throws SQLException JavaDoc {
1623        checkClosed();
1624
1625        BindValue binding = getBinding(parameterIndex, false);
1626        setType(binding, MysqlDefs.FIELD_TYPE_FLOAT);
1627
1628        binding.value = null;
1629        binding.floatBinding = x;
1630        binding.isNull = false;
1631        binding.isLongData = false;
1632    }
1633
1634    /**
1635     * @see java.sql.PreparedStatement#setInt(int, int)
1636     */

1637    public void setInt(int parameterIndex, int x) throws SQLException JavaDoc {
1638        checkClosed();
1639
1640        BindValue binding = getBinding(parameterIndex, false);
1641        setType(binding, MysqlDefs.FIELD_TYPE_LONG);
1642
1643        binding.value = null;
1644        binding.intBinding = x;
1645        binding.isNull = false;
1646        binding.isLongData = false;
1647    }
1648
1649    /**
1650     * @see java.sql.PreparedStatement#setLong(int, long)
1651     */

1652    public void setLong(int parameterIndex, long x) throws SQLException JavaDoc {
1653        checkClosed();
1654
1655        BindValue binding = getBinding(parameterIndex, false);
1656        setType(binding, MysqlDefs.FIELD_TYPE_LONGLONG);
1657
1658        binding.value = null;
1659        binding.longBinding = x;
1660        binding.isNull = false;
1661        binding.isLongData = false;
1662    }
1663
1664    /**
1665     * @see java.sql.PreparedStatement#setNull(int, int)
1666     */

1667    public void setNull(int parameterIndex, int sqlType) throws SQLException JavaDoc {
1668        checkClosed();
1669
1670        BindValue binding = getBinding(parameterIndex, false);
1671
1672        //
1673
// Don't re-set types, but use something if this
1674
// parameter was never specified
1675
//
1676
if (binding.bufferType == 0) {
1677            setType(binding, MysqlDefs.FIELD_TYPE_NULL);
1678        }
1679
1680        binding.value = null;
1681        binding.isNull = true;
1682        binding.isLongData = false;
1683    }
1684
1685    /**
1686     * @see java.sql.PreparedStatement#setNull(int, int, java.lang.String)
1687     */

1688    public void setNull(int parameterIndex, int sqlType, String JavaDoc typeName)
1689            throws SQLException JavaDoc {
1690        checkClosed();
1691
1692        BindValue binding = getBinding(parameterIndex, false);
1693
1694        //
1695
// Don't re-set types, but use something if this
1696
// parameter was never specified
1697
//
1698
if (binding.bufferType == 0) {
1699            setType(binding, MysqlDefs.FIELD_TYPE_NULL);
1700        }
1701
1702        binding.value = null;
1703        binding.isNull = true;
1704        binding.isLongData = false;
1705    }
1706
1707    /**
1708     * @see java.sql.PreparedStatement#setRef(int, java.sql.Ref)
1709     */

1710    public void setRef(int i, Ref JavaDoc x) throws SQLException JavaDoc {
1711        throw new NotImplemented();
1712    }
1713
1714    /**
1715     * @see java.sql.PreparedStatement#setShort(int, short)
1716     */

1717    public void setShort(int parameterIndex, short x) throws SQLException JavaDoc {
1718        checkClosed();
1719
1720        BindValue binding = getBinding(parameterIndex, false);
1721        setType(binding, MysqlDefs.FIELD_TYPE_SHORT);
1722
1723        binding.value = null;
1724        binding.shortBinding = x;
1725        binding.isNull = false;
1726        binding.isLongData = false;
1727    }
1728
1729    /**
1730     * @see java.sql.PreparedStatement#setString(int, java.lang.String)
1731     */

1732    public void setString(int parameterIndex, String JavaDoc x) throws SQLException JavaDoc {
1733        checkClosed();
1734
1735        if (x == null) {
1736            setNull(parameterIndex, java.sql.Types.CHAR);
1737        } else {
1738            BindValue binding = getBinding(parameterIndex, false);
1739
1740            setType(binding, this.stringTypeCode);
1741
1742            binding.value = x;
1743            binding.isNull = false;
1744            binding.isLongData = false;
1745        }
1746    }
1747
1748    /**
1749     * Set a parameter to a java.sql.Time value.
1750     *
1751     * @param parameterIndex
1752     * the first parameter is 1...));
1753     * @param x
1754     * the parameter value
1755     *
1756     * @throws SQLException
1757     * if a database access error occurs
1758     */

1759    public void setTime(int parameterIndex, java.sql.Time JavaDoc x)
1760            throws SQLException JavaDoc {
1761        setTimeInternal(parameterIndex, x, TimeZone.getDefault(), false);
1762    }
1763
1764    /**
1765     * Set a parameter to a java.sql.Time value. The driver converts this to a
1766     * SQL TIME value when it sends it to the database, using the given
1767     * timezone.
1768     *
1769     * @param parameterIndex
1770     * the first parameter is 1...));
1771     * @param x
1772     * the parameter value
1773     * @param cal
1774     * the timezone to use
1775     *
1776     * @throws SQLException
1777     * if a database access error occurs
1778     */

1779    public void setTime(int parameterIndex, java.sql.Time JavaDoc x, Calendar JavaDoc cal)
1780            throws SQLException JavaDoc {
1781        setTimeInternal(parameterIndex, x, cal.getTimeZone(), true);
1782    }
1783
1784    /**
1785     * Set a parameter to a java.sql.Time value. The driver converts this to a
1786     * SQL TIME value when it sends it to the database, using the given
1787     * timezone.
1788     *
1789     * @param parameterIndex
1790     * the first parameter is 1...));
1791     * @param x
1792     * the parameter value
1793     * @param tz
1794     * the timezone to use
1795     *
1796     * @throws SQLException
1797     * if a database access error occurs
1798     */

1799    public void setTimeInternal(int parameterIndex, java.sql.Time JavaDoc x,
1800            TimeZone JavaDoc tz, boolean rollForward) throws SQLException JavaDoc {
1801        if (x == null) {
1802            setNull(parameterIndex, java.sql.Types.TIME);
1803        } else {
1804            BindValue binding = getBinding(parameterIndex, false);
1805            setType(binding, MysqlDefs.FIELD_TYPE_TIME);
1806
1807            binding.value = TimeUtil.changeTimezone(this.connection, x, tz,
1808                    this.connection.getServerTimezoneTZ(), rollForward);
1809            binding.isNull = false;
1810            binding.isLongData = false;
1811        }
1812    }
1813
1814    /**
1815     * Set a parameter to a java.sql.Timestamp value. The driver converts this
1816     * to a SQL TIMESTAMP value when it sends it to the database.
1817     *
1818     * @param parameterIndex
1819     * the first parameter is 1, the second is 2, ...
1820     * @param x
1821     * the parameter value
1822     *
1823     * @throws SQLException
1824     * if a database-access error occurs.
1825     */

1826    public void setTimestamp(int parameterIndex, java.sql.Timestamp JavaDoc x)
1827            throws SQLException JavaDoc {
1828        setTimestampInternal(parameterIndex, x, TimeZone.getDefault(), false);
1829    }
1830
1831    /**
1832     * Set a parameter to a java.sql.Timestamp value. The driver converts this
1833     * to a SQL TIMESTAMP value when it sends it to the database.
1834     *
1835     * @param parameterIndex
1836     * the first parameter is 1, the second is 2, ...
1837     * @param x
1838     * the parameter value
1839     * @param cal
1840     * the timezone to use
1841     *
1842     * @throws SQLException
1843     * if a database-access error occurs.
1844     */

1845    public void setTimestamp(int parameterIndex, java.sql.Timestamp JavaDoc x,
1846            Calendar JavaDoc cal) throws SQLException JavaDoc {
1847        setTimestampInternal(parameterIndex, x, cal.getTimeZone(), true);
1848    }
1849
1850    protected void setTimestampInternal(int parameterIndex,
1851            java.sql.Timestamp JavaDoc x, TimeZone JavaDoc tz, boolean rollForward)
1852            throws SQLException JavaDoc {
1853        if (x == null) {
1854            setNull(parameterIndex, java.sql.Types.TIMESTAMP);
1855        } else {
1856            BindValue binding = getBinding(parameterIndex, false);
1857            setType(binding, MysqlDefs.FIELD_TYPE_DATETIME);
1858
1859            binding.value = TimeUtil.changeTimezone(this.connection, x, tz,
1860                    this.connection.getServerTimezoneTZ(), rollForward);
1861            binding.isNull = false;
1862            binding.isLongData = false;
1863        }
1864    }
1865
1866    private void setType(BindValue oldValue, int bufferType) {
1867        if (oldValue.bufferType != bufferType) {
1868            this.sendTypesToServer = true;
1869        }
1870
1871        oldValue.bufferType = bufferType;
1872    }
1873
1874    /**
1875     * DOCUMENT ME!
1876     *
1877     * @param parameterIndex
1878     * DOCUMENT ME!
1879     * @param x
1880     * DOCUMENT ME!
1881     * @param length
1882     * DOCUMENT ME!
1883     *
1884     * @throws SQLException
1885     * DOCUMENT ME!
1886     * @throws NotImplemented
1887     * DOCUMENT ME!
1888     *
1889     * @see java.sql.PreparedStatement#setUnicodeStream(int,
1890     * java.io.InputStream, int)
1891     * @deprecated
1892     */

1893    public void setUnicodeStream(int parameterIndex, InputStream JavaDoc x, int length)
1894            throws SQLException JavaDoc {
1895        checkClosed();
1896
1897        throw new NotImplemented();
1898    }
1899
1900    /**
1901     * @see java.sql.PreparedStatement#setURL(int, java.net.URL)
1902     */

1903    public void setURL(int parameterIndex, URL JavaDoc x) throws SQLException JavaDoc {
1904        checkClosed();
1905
1906        setString(parameterIndex, x.toString());
1907    }
1908
1909    /**
1910     * Method storeBinding.
1911     *
1912     * @param packet
1913     * @param bindValue
1914     * @param mysql
1915     * DOCUMENT ME!
1916     *
1917     * @throws SQLException
1918     * DOCUMENT ME!
1919     */

1920    private void storeBinding(Buffer packet, BindValue bindValue, MysqlIO mysql)
1921            throws SQLException JavaDoc {
1922        try {
1923            Object JavaDoc value = bindValue.value;
1924
1925            //
1926
// Handle primitives first
1927
//
1928
switch (bindValue.bufferType) {
1929
1930            case MysqlDefs.FIELD_TYPE_TINY:
1931                packet.writeByte(bindValue.byteBinding);
1932                return;
1933            case MysqlDefs.FIELD_TYPE_SHORT:
1934                packet.ensureCapacity(2);
1935                packet.writeInt(bindValue.shortBinding);
1936                return;
1937            case MysqlDefs.FIELD_TYPE_LONG:
1938                packet.ensureCapacity(4);
1939                packet.writeLong(bindValue.intBinding);
1940                return;
1941            case MysqlDefs.FIELD_TYPE_LONGLONG:
1942                packet.ensureCapacity(8);
1943                packet.writeLongLong(bindValue.longBinding);
1944                return;
1945            case MysqlDefs.FIELD_TYPE_FLOAT:
1946                packet.ensureCapacity(4);
1947                packet.writeFloat(bindValue.floatBinding);
1948                return;
1949            case MysqlDefs.FIELD_TYPE_DOUBLE:
1950                packet.ensureCapacity(8);
1951                packet.writeDouble(bindValue.doubleBinding);
1952                return;
1953            case MysqlDefs.FIELD_TYPE_TIME:
1954                storeTime(packet, (Time JavaDoc) value);
1955                return;
1956            case MysqlDefs.FIELD_TYPE_DATE:
1957            case MysqlDefs.FIELD_TYPE_DATETIME:
1958            case MysqlDefs.FIELD_TYPE_TIMESTAMP:
1959                storeDateTime(packet, (java.util.Date JavaDoc) value, mysql);
1960                return;
1961            case MysqlDefs.FIELD_TYPE_VAR_STRING:
1962            case MysqlDefs.FIELD_TYPE_STRING:
1963            case MysqlDefs.FIELD_TYPE_VARCHAR:
1964                if (!this.isLoadDataQuery) {
1965                    packet.writeLenString((String JavaDoc) value, this.charEncoding,
1966                            this.connection.getServerCharacterEncoding(),
1967                            this.charConverter, this.connection
1968                                    .parserKnowsUnicode());
1969                } else {
1970                    packet.writeLenBytes(((String JavaDoc) value).getBytes());
1971                }
1972
1973                return;
1974            }
1975
1976            if (value instanceof byte[]) {
1977                packet.writeLenBytes((byte[]) value);
1978            }
1979        } catch (UnsupportedEncodingException JavaDoc uEE) {
1980            throw new SQLException JavaDoc(Messages
1981                    .getString("ServerPreparedStatement.22") //$NON-NLS-1$
1982
+ this.connection.getEncoding() + "'", //$NON-NLS-1$
1983
SQLError.SQL_STATE_GENERAL_ERROR);
1984        }
1985    }
1986
1987    private void storeDataTime412AndOlder(Buffer intoBuf, java.util.Date JavaDoc dt)
1988            throws SQLException JavaDoc {
1989        // This is synchronized on the connection by callers, so it is
1990
// safe to lazily-instantiate this...
1991
if (this.dateTimeBindingCal == null) {
1992            this.dateTimeBindingCal = Calendar.getInstance();
1993        }
1994
1995        this.dateTimeBindingCal.setTime(dt);
1996
1997        intoBuf.ensureCapacity(8);
1998        intoBuf.writeByte((byte) 7); // length
1999

2000        int year = this.dateTimeBindingCal.get(Calendar.YEAR);
2001        int month = this.dateTimeBindingCal.get(Calendar.MONTH) + 1;
2002        int date = this.dateTimeBindingCal.get(Calendar.DATE);
2003
2004        intoBuf.writeInt(year);
2005        intoBuf.writeByte((byte) month);
2006        intoBuf.writeByte((byte) date);
2007
2008        if (dt instanceof java.sql.Date JavaDoc) {
2009            intoBuf.writeByte((byte) 0);
2010            intoBuf.writeByte((byte) 0);
2011            intoBuf.writeByte((byte) 0);
2012        } else {
2013            intoBuf.writeByte((byte) this.dateTimeBindingCal
2014                    .get(Calendar.HOUR_OF_DAY));
2015            intoBuf.writeByte((byte) this.dateTimeBindingCal
2016                    .get(Calendar.MINUTE));
2017            intoBuf.writeByte((byte) this.dateTimeBindingCal
2018                    .get(Calendar.SECOND));
2019        }
2020    }
2021
2022    private void storeDateTime(Buffer intoBuf, java.util.Date JavaDoc dt, MysqlIO mysql)
2023            throws SQLException JavaDoc {
2024        if (this.connection.versionMeetsMinimum(4, 1, 3)) {
2025            storeDateTime413AndNewer(intoBuf, dt);
2026        } else {
2027            storeDataTime412AndOlder(intoBuf, dt);
2028        }
2029    }
2030
2031    private void storeDateTime413AndNewer(Buffer intoBuf, java.util.Date JavaDoc dt)
2032            throws SQLException JavaDoc {
2033        // This is synchronized on the connection by callers, so it is
2034
// safe to lazily-instantiate this...
2035
if (this.dateTimeBindingCal == null) {
2036            this.dateTimeBindingCal = Calendar.getInstance();
2037        }
2038
2039        this.dateTimeBindingCal.setTime(dt);
2040
2041        byte length = (byte) 7;
2042
2043        intoBuf.ensureCapacity(length);
2044
2045        if (dt instanceof java.sql.Timestamp JavaDoc) {
2046            length = (byte) 11;
2047        }
2048
2049        intoBuf.writeByte(length); // length
2050

2051        int year = this.dateTimeBindingCal.get(Calendar.YEAR);
2052        int month = this.dateTimeBindingCal.get(Calendar.MONTH) + 1;
2053        int date = this.dateTimeBindingCal.get(Calendar.DATE);
2054
2055        intoBuf.writeInt(year);
2056        intoBuf.writeByte((byte) month);
2057        intoBuf.writeByte((byte) date);
2058
2059        if (dt instanceof java.sql.Date JavaDoc) {
2060            intoBuf.writeByte((byte) 0);
2061            intoBuf.writeByte((byte) 0);
2062            intoBuf.writeByte((byte) 0);
2063        } else {
2064            intoBuf.writeByte((byte) this.dateTimeBindingCal
2065                    .get(Calendar.HOUR_OF_DAY));
2066            intoBuf.writeByte((byte) this.dateTimeBindingCal
2067                    .get(Calendar.MINUTE));
2068            intoBuf.writeByte((byte) this.dateTimeBindingCal
2069                    .get(Calendar.SECOND));
2070        }
2071
2072        if (length == 11) {
2073            intoBuf.writeLong(((java.sql.Timestamp JavaDoc) dt).getNanos());
2074        }
2075    }
2076
2077    //
2078
// TO DO: Investigate using NIO to do this faster
2079
//
2080
private void storeReader(MysqlIO mysql, int parameterIndex, Buffer packet,
2081            Reader JavaDoc inStream) throws SQLException JavaDoc {
2082        char[] buf = new char[8192];
2083
2084        int numRead = 0;
2085
2086        int bytesInPacket = 0;
2087        int totalBytesRead = 0;
2088        int bytesReadAtLastSend = 0;
2089        int packetIsFullAt = this.connection.getBlobSendChunkSize();
2090
2091        try {
2092            packet.clear();
2093            packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2094            packet.writeLong(this.serverStatementId);
2095            packet.writeInt((parameterIndex));
2096
2097            boolean readAny = false;
2098            
2099            while ((numRead = inStream.read(buf)) != -1) {
2100                readAny = true;
2101                
2102                byte[] valueAsBytes = StringUtils.getBytes(buf, null,
2103                        this.connection.getEncoding(), this.connection
2104                                .getServerCharacterEncoding(), 0, numRead,
2105                        this.connection.parserKnowsUnicode());
2106
2107                packet.writeBytesNoNull(valueAsBytes, 0, valueAsBytes.length);
2108
2109                bytesInPacket += valueAsBytes.length;
2110                totalBytesRead += valueAsBytes.length;
2111
2112                if (bytesInPacket >= packetIsFullAt) {
2113                    bytesReadAtLastSend = totalBytesRead;
2114
2115                    mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet,
2116                            true, null);
2117
2118                    bytesInPacket = 0;
2119                    packet.clear();
2120                    packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2121                    packet.writeLong(this.serverStatementId);
2122                    packet.writeInt((parameterIndex));
2123                }
2124            }
2125
2126            if (totalBytesRead != bytesReadAtLastSend) {
2127                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2128                        null);
2129            }
2130            
2131            if (!readAny) {
2132                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2133                        null);
2134            }
2135        } catch (IOException JavaDoc ioEx) {
2136            throw new SQLException JavaDoc(Messages
2137                    .getString("ServerPreparedStatement.24") //$NON-NLS-1$
2138
+ ioEx.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
2139        } finally {
2140            if (inStream != null) {
2141                try {
2142                    inStream.close();
2143                } catch (IOException JavaDoc ioEx) {
2144                    ; // ignore
2145
}
2146            }
2147        }
2148    }
2149
2150    private void storeStream(MysqlIO mysql, int parameterIndex, Buffer packet,
2151            InputStream JavaDoc inStream) throws SQLException JavaDoc {
2152        byte[] buf = new byte[16384];
2153
2154        int numRead = 0;
2155        
2156        try {
2157            int bytesInPacket = 0;
2158            int totalBytesRead = 0;
2159            int bytesReadAtLastSend = 0;
2160            int packetIsFullAt = this.connection.getBlobSendChunkSize();
2161
2162            packet.clear();
2163            packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2164            packet.writeLong(this.serverStatementId);
2165            packet.writeInt((parameterIndex));
2166
2167            boolean readAny = false;
2168            
2169            while ((numRead = inStream.read(buf)) != -1) {
2170
2171                readAny = true;
2172                
2173                packet.writeBytesNoNull(buf, 0, numRead);
2174                bytesInPacket += numRead;
2175                totalBytesRead += numRead;
2176
2177                if (bytesInPacket >= packetIsFullAt) {
2178                    bytesReadAtLastSend = totalBytesRead;
2179
2180                    mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet,
2181                            true, null);
2182
2183                    bytesInPacket = 0;
2184                    packet.clear();
2185                    packet.writeByte((byte) MysqlDefs.COM_LONG_DATA);
2186                    packet.writeLong(this.serverStatementId);
2187                    packet.writeInt((parameterIndex));
2188                }
2189            }
2190
2191            if (totalBytesRead != bytesReadAtLastSend) {
2192                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2193                        null);
2194            }
2195            
2196            if (!readAny) {
2197                mysql.sendCommand(MysqlDefs.COM_LONG_DATA, null, packet, true,
2198                        null);
2199            }
2200        } catch (IOException JavaDoc ioEx) {
2201            throw new SQLException JavaDoc(Messages
2202                    .getString("ServerPreparedStatement.25") //$NON-NLS-1$
2203
+ ioEx.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
2204        } finally {
2205            if (inStream != null) {
2206                try {
2207                    inStream.close();
2208                } catch (IOException JavaDoc ioEx) {
2209                    ; // ignore
2210
}
2211            }
2212        }
2213    }
2214
2215    /**
2216     * @see java.lang.Object#toString()
2217     */

2218    public String JavaDoc toString() {
2219        StringBuffer JavaDoc toStringBuf = new StringBuffer JavaDoc();
2220
2221        toStringBuf.append("com.mysql.jdbc.ServerPreparedStatement["); //$NON-NLS-1$
2222
toStringBuf.append(this.serverStatementId);
2223        toStringBuf.append("] - "); //$NON-NLS-1$
2224

2225        try {
2226            toStringBuf.append(asSql());
2227        } catch (SQLException JavaDoc sqlEx) {
2228            toStringBuf.append(Messages.getString("ServerPreparedStatement.6")); //$NON-NLS-1$
2229
toStringBuf.append(sqlEx);
2230        }
2231
2232        return toStringBuf.toString();
2233    }
2234}
2235
Popular Tags