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

COVERAGE SUMMARY FOR SOURCE FILE [PreparedStatement.java]

nameclass, %method, %block, %line, %
PreparedStatement.java75%  (3/4)87%  (77/89)78%  (4500/5791)80%  (950.7/1183)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class PreparedStatement$EndPoint0%   (0/1)0%   (0/1)0%   (0/12)0%   (0/4)
PreparedStatement$EndPoint (PreparedStatement, int, int): void 0%   (0/1)0%   (0/12)0%   (0/4)
     
class PreparedStatement100% (1/1)87%  (75/86)77%  (4057/5245)80%  (860.9/1072)
getParameterMetaData (): ParameterMetaData 0%   (0/1)0%   (0/14)0%   (0/3)
getParseInfo (): PreparedStatement$ParseInfo 0%   (0/1)0%   (0/3)0%   (0/1)
hexEscapeBlock (byte [], Buffer, int): void 0%   (0/1)0%   (0/34)0%   (0/7)
readblock (InputStream, byte []): int 0%   (0/1)0%   (0/21)0%   (0/3)
setArray (int, Array): void 0%   (0/1)0%   (0/4)0%   (0/1)
setAsciiStream (int, InputStream, int): void 0%   (0/1)0%   (0/13)0%   (0/4)
setNull (int, int, String): void 0%   (0/1)0%   (0/5)0%   (0/2)
setRef (int, Ref): void 0%   (0/1)0%   (0/4)0%   (0/1)
setSerializableObject (int, Object): void 0%   (0/1)0%   (0/53)0%   (0/14)
setURL (int, URL): void 0%   (0/1)0%   (0/13)0%   (0/4)
setUnicodeStream (int, InputStream, int): void 0%   (0/1)0%   (0/13)0%   (0/4)
readblock (InputStream, byte [], int): int 100% (1/1)47%  (15/32)67%  (4/6)
setCharacterStream (int, Reader, int): void 100% (1/1)47%  (35/74)56%  (10/18)
asSql (boolean): String 100% (1/1)50%  (86/173)52%  (15/29)
escapeblockFast (byte [], ByteArrayOutputStream, int): void 100% (1/1)51%  (38/74)47%  (8/17)
streamToBytes (InputStream, boolean, int, boolean): byte [] 100% (1/1)53%  (69/131)54%  (18.9/35)
setBoolean (int, boolean): void 100% (1/1)62%  (13/21)75%  (3/4)
execute (): boolean 100% (1/1)62%  (138/222)74%  (27.4/37)
toString (): String 100% (1/1)63%  (22/35)75%  (6/8)
setOneBatchedParameterSet (PreparedStatement, int, PreparedStatement$BatchPar... 100% (1/1)63%  (33/52)78%  (7/9)
setBigDecimal (int, BigDecimal): void 100% (1/1)64%  (9/14)75%  (3/4)
setBinaryStream (int, InputStream, int): void 100% (1/1)65%  (44/68)89%  (8/9)
executeQuery (): ResultSet 100% (1/1)65%  (135/208)74%  (25.9/35)
setNumericObject (int, Object, int, int): void 100% (1/1)66%  (107/163)78%  (31/40)
setObject (int, Object, int, int): void 100% (1/1)69%  (213/308)80%  (48.6/61)
streamToBytes (Buffer, InputStream, boolean, int, boolean): void 100% (1/1)70%  (100/143)77%  (29.3/38)
setInternal (int, byte []): void 100% (1/1)72%  (63/87)82%  (9/11)
setDate (int, Date): void 100% (1/1)75%  (15/20)80%  (4/5)
getMetaData (): ResultSetMetaData 100% (1/1)75%  (76/101)78%  (25.7/33)
setObject (int, Object): void 100% (1/1)76%  (142/186)82%  (33/40)
computeBatchSize (int): int 100% (1/1)76%  (91/119)79%  (19/24)
executeBatch (): int [] 100% (1/1)78%  (52/67)90%  (9/10)
getDateTimePattern (String, boolean): String 100% (1/1)81%  (398/492)84%  (76.3/91)
executeUpdate (byte [][], InputStream [], boolean [], int [], boolean [], boo... 100% (1/1)82%  (143/174)86%  (31/36)
extractValuesClause (): String 100% (1/1)83%  (58/70)75%  (12/16)
setTimeInternal (int, Time, TimeZone, boolean): void 100% (1/1)84%  (27/32)80%  (4/5)
setBlob (int, Blob): void 100% (1/1)86%  (30/35)88%  (7/8)
setTimestampInternal (int, Timestamp, TimeZone, boolean): void 100% (1/1)87%  (34/39)89%  (8/9)
executeBatchedInserts (): int [] 100% (1/1)91%  (167/183)91%  (40/44)
setString (int, String): void 100% (1/1)91%  (129/141)92%  (36/39)
PreparedStatement (Connection, String, String, PreparedStatement$ParseInfo): ... 100% (1/1)92%  (87/95)96%  (25/26)
PreparedStatement (Connection, String, String): void 100% (1/1)93%  (91/98)96%  (24/25)
executeBatchSerially (): int [] 100% (1/1)96%  (160/167)97%  (32.8/34)
getBytesRepresentation (int): byte [] 100% (1/1)97%  (59/61)90%  (9/10)
setBytes (int, byte [], boolean, boolean): void 100% (1/1)98%  (204/209)98%  (57/58)
<static initializer> 100% (1/1)100% (68/68)100% (1/1)
PreparedStatement (Connection, String): void 100% (1/1)100% (56/56)100% (18/18)
addBatch (): void 100% (1/1)100% (27/27)100% (4/4)
addBatch (String): void 100% (1/1)100% (7/7)100% (3/3)
asSql (): String 100% (1/1)100% (4/4)100% (1/1)
clearBatch (): void 100% (1/1)100% (6/6)100% (3/3)
clearParameters (): void 100% (1/1)100% (32/32)100% (7/7)
close (): void 100% (1/1)100% (4/4)100% (2/2)
escapeblockFast (byte [], Buffer, int): void 100% (1/1)100% (74/74)100% (17/17)
executeInternal (int, Buffer, boolean, boolean, boolean, boolean): ResultSet 100% (1/1)100% (27/27)100% (3/3)
executeUpdate (): int 100% (1/1)100% (4/4)100% (1/1)
executeUpdate (boolean): int 100% (1/1)100% (21/21)100% (4/4)
fillSendPacket (): Buffer 100% (1/1)100% (11/11)100% (1/1)
fillSendPacket (byte [][], InputStream [], boolean [], int []): Buffer 100% (1/1)100% (109/109)100% (19/19)
generateBatchedInsertSQL (String, int): String 100% (1/1)100% (39/39)100% (6/6)
getSuccessor (char, int): char 100% (1/1)100% (91/91)100% (1/1)
initializeFromParseInfo (): void 100% (1/1)100% (68/68)100% (14/14)
isNull (int): boolean 100% (1/1)100% (5/5)100% (1/1)
readFully (Reader, char [], int): int 100% (1/1)100% (23/23)100% (7/7)
realClose (boolean): void 100% (1/1)100% (65/65)100% (15/15)
setByte (int, byte): void 100% (1/1)100% (6/6)100% (2/2)
setBytes (int, byte []): void 100% (1/1)100% (7/7)100% (2/2)
setBytesNoEscape (int, byte []): void 100% (1/1)100% (29/29)100% (6/6)
setBytesNoEscapeNoQuotes (int, byte []): void 100% (1/1)100% (5/5)100% (2/2)
setClob (int, Clob): void 100% (1/1)100% (17/17)100% (5/5)
setDate (int, Date, Calendar): void 100% (1/1)100% (5/5)100% (2/2)
setDouble (int, double): void 100% (1/1)100% (37/37)100% (4/4)
setFloat (int, float): void 100% (1/1)100% (7/7)100% (2/2)
setInt (int, int): void 100% (1/1)100% (6/6)100% (2/2)
setInternal (int, String): void 100% (1/1)100% (29/29)100% (6/6)
setLong (int, long): void 100% (1/1)100% (6/6)100% (2/2)
setNull (int, int): void 100% (1/1)100% (12/12)100% (3/3)
setObject (int, Object, int): void 100% (1/1)100% (19/19)100% (4/4)
setResultSetConcurrency (int): void 100% (1/1)100% (4/4)100% (2/2)
setResultSetType (int): void 100% (1/1)100% (4/4)100% (2/2)
setRetrieveGeneratedKeys (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setShort (int, short): void 100% (1/1)100% (6/6)100% (2/2)
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)
     
class PreparedStatement$ParseInfo100% (1/1)100% (1/1)80%  (356/447)81%  (72.8/90)
PreparedStatement$ParseInfo (PreparedStatement, String, Connection, DatabaseM... 100% (1/1)80%  (356/447)81%  (72.8/90)
     
class PreparedStatement$BatchParams100% (1/1)100% (1/1)100% (87/87)100% (17/17)
PreparedStatement$BatchParams (PreparedStatement, byte [][], InputStream [], ... 100% (1/1)100% (87/87)100% (17/17)

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 java.io.ByteArrayInputStream;
28import java.io.ByteArrayOutputStream;
29import java.io.IOException;
30import java.io.InputStream;
31import java.io.ObjectOutputStream;
32import java.io.Reader;
33import java.io.StringReader;
34import java.io.UnsupportedEncodingException;
35import java.math.BigDecimal;
36import java.math.BigInteger;
37import java.net.URL;
38import java.sql.Array;
39import java.sql.Clob;
40import java.sql.ParameterMetaData;
41import java.sql.Ref;
42import java.sql.SQLException;
43import java.sql.Time;
44import java.sql.Timestamp;
45import java.sql.Types;
46import java.text.ParsePosition;
47import java.text.SimpleDateFormat;
48import java.util.ArrayList;
49import java.util.Calendar;
50import java.util.Locale;
51import java.util.TimeZone;
52 
53import com.mysql.jdbc.profiler.ProfilerEvent;
54 
55/**
56 * A SQL Statement is pre-compiled and stored in a PreparedStatement object.
57 * This object can then be used to efficiently execute this statement multiple
58 * times.
59 * 
60 * <p>
61 * <B>Note:</B> The setXXX methods for setting IN parameter values must specify
62 * types that are compatible with the defined SQL type of the input parameter.
63 * For instance, if the IN parameter has SQL type Integer, then setInt should be
64 * used.
65 * </p>
66 * 
67 * <p>
68 * If arbitrary parameter type conversions are required, then the setObject
69 * method should be used with a target SQL type.
70 * </p>
71 * 
72 * @author Mark Matthews
73 * @version $Id: PreparedStatement.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
74 *          Exp $
75 * 
76 * @see java.sql.ResultSet
77 * @see java.sql.PreparedStatement
78 */
79public class PreparedStatement extends com.mysql.jdbc.Statement implements
80                java.sql.PreparedStatement {
81        class BatchParams {
82                boolean[] isNull = null;
83 
84                boolean[] isStream = null;
85 
86                InputStream[] parameterStreams = null;
87 
88                byte[][] parameterStrings = null;
89 
90                int[] streamLengths = null;
91 
92                BatchParams(byte[][] strings, InputStream[] streams,
93                                boolean[] isStreamFlags, int[] lengths, boolean[] isNullFlags) {
94                        //
95                        // Make copies
96                        //
97                        this.parameterStrings = new byte[strings.length][];
98                        this.parameterStreams = new InputStream[streams.length];
99                        this.isStream = new boolean[isStreamFlags.length];
100                        this.streamLengths = new int[lengths.length];
101                        this.isNull = new boolean[isNullFlags.length];
102                        System.arraycopy(strings, 0, this.parameterStrings, 0,
103                                        strings.length);
104                        System.arraycopy(streams, 0, this.parameterStreams, 0,
105                                        streams.length);
106                        System.arraycopy(isStreamFlags, 0, this.isStream, 0,
107                                        isStreamFlags.length);
108                        System.arraycopy(lengths, 0, this.streamLengths, 0, lengths.length);
109                        System
110                                        .arraycopy(isNullFlags, 0, this.isNull, 0,
111                                                        isNullFlags.length);
112                }
113        }
114 
115        class EndPoint {
116                int begin;
117 
118                int end;
119 
120                EndPoint(int b, int e) {
121                        this.begin = b;
122                        this.end = e;
123                }
124        }
125 
126        class ParseInfo {
127                char firstStmtChar = 0;
128 
129                boolean foundLimitClause = false;
130 
131                boolean foundLoadData = false;
132 
133                long lastUsed = 0;
134 
135                int statementLength = 0;
136 
137                byte[][] staticSql = null;
138 
139                /**
140                 * 
141                 */
142                public ParseInfo(String sql, Connection conn,
143                                java.sql.DatabaseMetaData dbmd, String encoding,
144                                SingleByteCharsetConverter converter) throws SQLException {
145                        if (sql == null) {
146                                throw new SQLException(Messages
147                                                .getString("PreparedStatement.61"), //$NON-NLS-1$
148                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
149                        }
150 
151                        this.lastUsed = System.currentTimeMillis();
152 
153                        String quotedIdentifierString = dbmd.getIdentifierQuoteString();
154 
155                        char quotedIdentifierChar = 0;
156 
157                        if ((quotedIdentifierString != null)
158                                        && !quotedIdentifierString.equals(" ") //$NON-NLS-1$
159                                        && (quotedIdentifierString.length() > 0)) {
160                                quotedIdentifierChar = quotedIdentifierString.charAt(0);
161                        }
162 
163                        this.statementLength = sql.length();
164 
165                        ArrayList endpointList = new ArrayList();
166                        boolean inQuotes = false;
167                        char quoteChar = 0;
168                        boolean inQuotedId = false;
169                        int lastParmEnd = 0;
170                        int i;
171 
172                        int pre1 = 0;
173                        int pre2 = 0;
174 
175                        int stopLookingForLimitClause = this.statementLength - 5;
176 
177                        this.foundLimitClause = false;
178 
179                        for (i = 0; i < this.statementLength; ++i) {
180                                char c = sql.charAt(i);
181 
182                                if ((this.firstStmtChar == 0) && !Character.isWhitespace(c)) {
183                                        // Determine what kind of statement we're doing (_S_elect,
184                                        // _I_nsert, etc.)
185                                        this.firstStmtChar = Character.toUpperCase(c);
186                                }
187 
188                                // are we in a quoted identifier?
189                                // (only valid when the id is not inside a 'string')
190                                if (!inQuotes && (quotedIdentifierChar != 0)
191                                                && (c == quotedIdentifierChar)) {
192                                        inQuotedId = !inQuotedId;
193                                } else if (!inQuotedId) {
194                                        //        only respect quotes when not in a quoted identifier
195                                        
196                                        if (inQuotes) {
197                                                if ((((c == '\'') || (c == '"')) && c == quoteChar)
198                                                                && (pre1 == '\\') && (pre2 != '\\')) {
199                                                        inQuotes = !inQuotes;
200                                                        quoteChar = 0;
201                                                } else if ((((c == '\'') || (c == '"')) && c == quoteChar)
202                                                                && (pre1 != '\\')) {
203                                                        inQuotes = !inQuotes;
204                                                        quoteChar = 0;
205                                                }
206                                        } else {
207                                                if (((c == '\'') || (c == '"')) && (pre1 == '\\')
208                                                                && (pre2 != '\\')) {
209                                                        inQuotes = true;
210                                                        quoteChar = c;
211                                                } else if (((c == '\'') || (c == '"'))
212                                                                && (pre1 != '\\')) {
213                                                        inQuotes = true;
214                                                        quoteChar = c;
215                                                }
216                                        }
217                                }
218 
219                                if ((c == '?') && !inQuotes && !inQuotedId) {
220                                        endpointList.add(new int[] { lastParmEnd, i });
221                                        lastParmEnd = i + 1;
222                                }
223 
224                                if (!inQuotes && (i < stopLookingForLimitClause)) {
225                                        if ((c == 'L') || (c == 'l')) {
226                                                char posI1 = sql.charAt(i + 1);
227 
228                                                if ((posI1 == 'I') || (posI1 == 'i')) {
229                                                        char posM = sql.charAt(i + 2);
230 
231                                                        if ((posM == 'M') || (posM == 'm')) {
232                                                                char posI2 = sql.charAt(i + 3);
233 
234                                                                if ((posI2 == 'I') || (posI2 == 'i')) {
235                                                                        char posT = sql.charAt(i + 4);
236 
237                                                                        if ((posT == 'T') || (posT == 't')) {
238                                                                                foundLimitClause = true;
239                                                                        }
240                                                                }
241                                                        }
242                                                }
243                                        }
244                                }
245 
246                                pre2 = pre1;
247                                pre1 = c;
248                        }
249 
250                        if (this.firstStmtChar == 'L') {
251                                if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) { //$NON-NLS-1$
252                                        this.foundLoadData = true;
253                                } else {
254                                        this.foundLoadData = false;
255                                }
256                        } else {
257                                this.foundLoadData = false;
258                        }
259 
260                        endpointList.add(new int[] { lastParmEnd, this.statementLength });
261                        this.staticSql = new byte[endpointList.size()][];
262                        char[] asCharArray = null;
263 
264                        for (i = 0; i < this.staticSql.length; i++) {
265                                int[] ep = (int[]) endpointList.get(i);
266                                int end = ep[1];
267                                int begin = ep[0];
268                                int len = end - begin;
269 
270                                if (this.foundLoadData) {
271                                        if (asCharArray == null) {
272                                                asCharArray = sql.toCharArray();
273                                        }
274 
275                                        String temp = new String(asCharArray, begin, len);
276                                        this.staticSql[i] = temp.getBytes();
277                                } else if (encoding == null) {
278                                        byte[] buf = new byte[len];
279 
280                                        for (int j = 0; j < len; j++) {
281                                                buf[j] = (byte) sql.charAt(begin + j);
282                                        }
283 
284                                        this.staticSql[i] = buf;
285                                } else {
286                                        if (converter != null) {
287                                                this.staticSql[i] = StringUtils.getBytes(sql,
288                                                                converter, encoding, connection
289                                                                                .getServerCharacterEncoding(), begin,
290                                                                len, connection.parserKnowsUnicode());
291                                        } else {
292                                                if (asCharArray == null) {
293                                                        asCharArray = sql.toCharArray();
294                                                }
295 
296                                                String temp = new String(asCharArray, begin, len);
297 
298                                                this.staticSql[i] = StringUtils.getBytes(temp,
299                                                                encoding, connection
300                                                                                .getServerCharacterEncoding(),
301                                                                connection.parserKnowsUnicode());
302                                        }
303                                }
304                        }
305                }
306        }
307 
308        private final static byte[] HEX_DIGITS = new byte[] { (byte) '0',
309                        (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
310                        (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A',
311                        (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F' };
312 
313        /**
314         * Reads length bytes from reader into buf. Blocks until enough input is
315         * available
316         * 
317         * @param reader
318         *            DOCUMENT ME!
319         * @param buf
320         *            DOCUMENT ME!
321         * @param length
322         *            DOCUMENT ME!
323         * 
324         * @return DOCUMENT ME!
325         * 
326         * @throws IOException
327         *             DOCUMENT ME!
328         */
329        private static int readFully(Reader reader, char[] buf, int length)
330                        throws IOException {
331                int numCharsRead = 0;
332 
333                while (numCharsRead < length) {
334                        int count = reader.read(buf, numCharsRead, length - numCharsRead);
335 
336                        if (count < 0) {
337                                break;
338                        }
339 
340                        numCharsRead += count;
341                }
342 
343                return numCharsRead;
344        }
345 
346        /**
347         * Does the batch (if any) contain "plain" statements added by
348         * Statement.addBatch(String)?
349         * 
350         * If so, we can't re-write it to use multi-value or multi-queries.
351         */
352        protected boolean batchHasPlainStatements = false;
353 
354        private java.sql.DatabaseMetaData dbmd = null;
355 
356        /**
357         * What is the first character of the prepared statement (used to check for
358         * SELECT vs. INSERT/UPDATE/DELETE)
359         */
360        protected char firstCharOfStmt = 0;
361 
362        /** Does the SQL for this statement contain a 'limit' clause? */
363        protected boolean hasLimitClause = false;
364 
365        /** Is this query a LOAD DATA query? */
366        protected boolean isLoadDataQuery = false;
367 
368        private boolean[] isNull = null;
369 
370        private boolean[] isStream = null;
371 
372        protected int numberOfExecutions = 0;
373 
374        /** The SQL that was passed in to 'prepare' */
375        protected String originalSql = null;
376 
377        /** The number of parameters in this PreparedStatement */
378        protected int parameterCount;
379 
380        protected MysqlParameterMetadata parameterMetaData;
381 
382        private InputStream[] parameterStreams = null;
383 
384        private byte[][] parameterValues = null;
385 
386        private ParseInfo parseInfo;
387 
388        private java.sql.ResultSetMetaData pstmtResultMetaData;
389 
390        private byte[][] staticSqlStrings = null;
391 
392        private byte[] streamConvertBuf = new byte[4096];
393 
394        private int[] streamLengths = null;
395 
396        private SimpleDateFormat tsdf = null;
397 
398        /**
399         * Are we using a version of MySQL where we can use 'true' boolean values?
400         */
401        protected boolean useTrueBoolean = false;
402 
403        private boolean usingAnsiMode;
404 
405        private String batchedValuesClause;
406 
407        /**
408         * Constructor used by server-side prepared statements
409         * 
410         * @param conn
411         *            the connection that created us
412         * @param catalog
413         *            the catalog in use when we were created
414         * 
415         * @throws SQLException
416         *             if an error occurs
417         */
418        protected PreparedStatement(Connection conn, String catalog)
419                        throws SQLException {
420                super(conn, catalog);
421        }
422 
423        /**
424         * Constructor for the PreparedStatement class.
425         * 
426         * @param conn
427         *            the connection creating this statement
428         * @param sql
429         *            the SQL for this statement
430         * @param catalog
431         *            the catalog/database this statement should be issued against
432         * 
433         * @throws SQLException
434         *             if a database error occurs.
435         */
436        public PreparedStatement(Connection conn, String sql, String catalog)
437                        throws SQLException {
438                super(conn, catalog);
439 
440                if (sql == null) {
441                        throw new SQLException(Messages.getString("PreparedStatement.0"), //$NON-NLS-1$
442                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
443                }
444 
445                this.originalSql = sql;
446 
447                this.dbmd = this.connection.getMetaData();
448 
449                this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
450 
451                this.parseInfo = new ParseInfo(sql, this.connection, this.dbmd,
452                                this.charEncoding, this.charConverter);
453 
454                initializeFromParseInfo();
455        }
456 
457        /**
458         * Creates a new PreparedStatement object.
459         * 
460         * @param conn
461         *            the connection creating this statement
462         * @param sql
463         *            the SQL for this statement
464         * @param catalog
465         *            the catalog/database this statement should be issued against
466         * @param cachedParseInfo
467         *            already created parseInfo.
468         * 
469         * @throws SQLException
470         *             DOCUMENT ME!
471         */
472        public PreparedStatement(Connection conn, String sql, String catalog,
473                        ParseInfo cachedParseInfo) throws SQLException {
474                super(conn, catalog);
475 
476                if (sql == null) {
477                        throw new SQLException(Messages.getString("PreparedStatement.1"), //$NON-NLS-1$
478                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
479                }
480 
481                this.originalSql = sql;
482 
483                this.dbmd = this.connection.getMetaData();
484 
485                this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
486 
487                this.parseInfo = cachedParseInfo;
488 
489                this.usingAnsiMode = !this.connection.useAnsiQuotedIdentifiers();
490 
491                initializeFromParseInfo();
492        }
493 
494        /**
495         * JDBC 2.0 Add a set of parameters to the batch.
496         * 
497         * @exception SQLException
498         *                if a database-access error occurs.
499         * 
500         * @see Statement#addBatch
501         */
502        public void addBatch() throws SQLException {
503                if (this.batchedArgs == null) {
504                        this.batchedArgs = new ArrayList();
505                }
506 
507                this.batchedArgs.add(new BatchParams(this.parameterValues,
508                                this.parameterStreams, this.isStream, this.streamLengths,
509                                this.isNull));
510        }
511 
512        public synchronized void addBatch(String sql) throws SQLException {
513                this.batchHasPlainStatements = true;
514 
515                super.addBatch(sql);
516        }
517 
518        protected String asSql() throws SQLException {
519                return asSql(false);
520        }
521 
522        protected String asSql(boolean quoteStreamsAndUnknowns) throws SQLException {
523                StringBuffer buf = new StringBuffer();
524 
525                try {
526                        for (int i = 0; i < this.parameterCount; ++i) {
527                                if (this.charEncoding != null) {
528                                        buf.append(new String(this.staticSqlStrings[i],
529                                                        this.charEncoding));
530                                } else {
531                                        buf.append(new String(this.staticSqlStrings[i]));
532                                }
533 
534                                if ((this.parameterValues[i] == null) && !this.isStream[i]) {
535                                        if (quoteStreamsAndUnknowns) {
536                                                buf.append("'");
537                                        }
538 
539                                        buf.append("** NOT SPECIFIED **"); //$NON-NLS-1$
540 
541                                        if (quoteStreamsAndUnknowns) {
542                                                buf.append("'");
543                                        }
544                                } else if (this.isStream[i]) {
545                                        if (quoteStreamsAndUnknowns) {
546                                                buf.append("'");
547                                        }
548 
549                                        buf.append("** STREAM DATA **"); //$NON-NLS-1$
550 
551                                        if (quoteStreamsAndUnknowns) {
552                                                buf.append("'");
553                                        }
554                                } else {
555                                        if (this.charConverter != null) {
556                                                buf.append(this.charConverter
557                                                                .toString(this.parameterValues[i]));
558                                        } else {
559                                                if (this.charEncoding != null) {
560                                                        buf.append(new String(this.parameterValues[i],
561                                                                        this.charEncoding));
562                                                } else {
563                                                        buf.append(StringUtils
564                                                                        .toAsciiString(this.parameterValues[i]));
565                                                }
566                                        }
567                                }
568                        }
569 
570                        if (this.charEncoding != null) {
571                                buf.append(new String(
572                                                this.staticSqlStrings[this.parameterCount],
573                                                this.charEncoding));
574                        } else {
575                                buf
576                                                .append(StringUtils
577                                                                .toAsciiString(this.staticSqlStrings[this.parameterCount]));
578                        }
579                } catch (UnsupportedEncodingException uue) {
580                        throw new RuntimeException(Messages
581                                        .getString("PreparedStatement.32") //$NON-NLS-1$
582                                        + this.charEncoding
583                                        + Messages.getString("PreparedStatement.33")); //$NON-NLS-1$
584                }
585 
586                return buf.toString();
587        }
588 
589        public synchronized void clearBatch() throws SQLException {
590                this.batchHasPlainStatements = false;
591 
592                super.clearBatch();
593        }
594 
595        /**
596         * In general, parameter values remain in force for repeated used of a
597         * Statement. Setting a parameter value automatically clears its previous
598         * value. However, in some cases, it is useful to immediately release the
599         * resources used by the current parameter values; this can be done by
600         * calling clearParameters
601         * 
602         * @exception SQLException
603         *                if a database access error occurs
604         */
605        public synchronized void clearParameters() throws SQLException {
606                checkClosed();
607                
608                for (int i = 0; i < this.parameterValues.length; i++) {
609                        this.parameterValues[i] = null;
610                        this.parameterStreams[i] = null;
611                        this.isStream[i] = false;
612                        this.isNull[i] = false;
613                }
614        }
615 
616        /**
617         * Closes this prepared statement and releases all resources.
618         * 
619         * @throws SQLException
620         *             if database error occurs.
621         */
622        public synchronized void close() throws SQLException {
623                realClose(true);
624        }
625 
626        private final void escapeblockFast(byte[] buf, Buffer packet, int size)
627                        throws SQLException {
628                int lastwritten = 0;
629 
630                for (int i = 0; i < size; i++) {
631                        byte b = buf[i];
632 
633                        if (b == '\0') {
634                                // write stuff not yet written
635                                if (i > lastwritten) {
636                                        packet.writeBytesNoNull(buf, lastwritten, i - lastwritten);
637                                }
638 
639                                // write escape
640                                packet.writeByte((byte) '\\');
641                                packet.writeByte((byte) '0');
642                                lastwritten = i + 1;
643                        } else {
644                                if ((b == '\\') || (b == '\'')
645                                                || (!this.usingAnsiMode && b == '"')) {
646                                        // write stuff not yet written
647                                        if (i > lastwritten) {
648                                                packet.writeBytesNoNull(buf, lastwritten, i
649                                                                - lastwritten);
650                                        }
651 
652                                        // write escape
653                                        packet.writeByte((byte) '\\');
654                                        lastwritten = i; // not i+1 as b wasn't written.
655                                }
656                        }
657                }
658 
659                // write out remaining stuff from buffer
660                if (lastwritten < size) {
661                        packet.writeBytesNoNull(buf, lastwritten, size - lastwritten);
662                }
663        }
664 
665        private final void escapeblockFast(byte[] buf,
666                        ByteArrayOutputStream bytesOut, int size) {
667                int lastwritten = 0;
668 
669                for (int i = 0; i < size; i++) {
670                        byte b = buf[i];
671 
672                        if (b == '\0') {
673                                // write stuff not yet written
674                                if (i > lastwritten) {
675                                        bytesOut.write(buf, lastwritten, i - lastwritten);
676                                }
677 
678                                // write escape
679                                bytesOut.write('\\');
680                                bytesOut.write('0');
681                                lastwritten = i + 1;
682                        } else {
683                                if ((b == '\\') || (b == '\'')
684                                                || (!this.usingAnsiMode && b == '"')) {
685                                        // write stuff not yet written
686                                        if (i > lastwritten) {
687                                                bytesOut.write(buf, lastwritten, i - lastwritten);
688                                        }
689 
690                                        // write escape
691                                        bytesOut.write('\\');
692                                        lastwritten = i; // not i+1 as b wasn't written.
693                                }
694                        }
695                }
696 
697                // write out remaining stuff from buffer
698                if (lastwritten < size) {
699                        bytesOut.write(buf, lastwritten, size - lastwritten);
700                }
701        }
702 
703        /**
704         * Some prepared statements return multiple results; the execute method
705         * handles these complex statements as well as the simpler form of
706         * statements handled by executeQuery and executeUpdate
707         * 
708         * @return true if the next result is a ResultSet; false if it is an update
709         *         count or there are no more results
710         * 
711         * @exception SQLException
712         *                if a database access error occurs
713         */
714        public boolean execute() throws SQLException {
715                if (this.connection.isReadOnly() && (this.firstCharOfStmt != 'S')) {
716                        throw new SQLException(Messages.getString("PreparedStatement.20") //$NON-NLS-1$
717                                        + Messages.getString("PreparedStatement.21"), //$NON-NLS-1$
718                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
719                }
720 
721                checkClosed();
722 
723                ResultSet rs = null;
724 
725                synchronized (this.connection.getMutex()) {
726                        clearWarnings();
727 
728                        this.batchedGeneratedKeys = null;
729 
730                        Buffer sendPacket = fillSendPacket();
731 
732                        String oldCatalog = null;
733 
734                        if (!this.connection.getCatalog().equals(this.currentCatalog)) {
735                                oldCatalog = this.connection.getCatalog();
736                                this.connection.setCatalog(this.currentCatalog);
737                        }
738 
739                        boolean oldInfoMsgState = false;
740 
741                        if (this.retrieveGeneratedKeys) {
742                                oldInfoMsgState = this.connection.isReadInfoMsgEnabled();
743                                this.connection.setReadInfoMsgEnabled(true);
744                        }
745 
746                        // If there isn't a limit clause in the SQL
747                        // then limit the number of rows to return in
748                        // an efficient manner. Only do this if
749                        // setMaxRows() hasn't been used on any Statements
750                        // generated from the current Connection (saves
751                        // a query, and network traffic).
752                        //
753                        // Only apply max_rows to selects
754                        //
755                        if (this.connection.useMaxRows()) {
756                                int rowLimit = -1;
757 
758                                if (this.firstCharOfStmt == 'S') {
759                                        if (this.hasLimitClause) {
760                                                rowLimit = this.maxRows;
761                                        } else {
762                                                if (this.maxRows <= 0) {
763                                                        this.connection.execSQL(
764                                                                        this,
765                                                                        "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, //$NON-NLS-1$
766                                                                        null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
767                                                                        java.sql.ResultSet.CONCUR_READ_ONLY, false,
768                                                                        false, this.currentCatalog, true);
769                                                } else {
770                                                        this.connection
771                                                                        .execSQL(
772                                                                                        this,
773                                                                                        "SET OPTION SQL_SELECT_LIMIT=" + this.maxRows, -1, //$NON-NLS-1$
774                                                                                        null,
775                                                                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
776                                                                                        java.sql.ResultSet.CONCUR_READ_ONLY,
777                                                                                        false, false, this.currentCatalog,
778                                                                                        true);
779                                                }
780                                        }
781                                } else {
782                                        this.connection.execSQL(this,
783                                                        "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
784                                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
785                                                        java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
786                                                        this.currentCatalog, true);
787                                }
788 
789                                // Finally, execute the query
790                                rs = executeInternal(rowLimit, sendPacket,
791                                                createStreamingResultSet(),
792                                                (this.firstCharOfStmt == 'S'), true, false);
793                        } else {
794                                rs = executeInternal(-1, sendPacket,
795                                                createStreamingResultSet(),
796                                                (this.firstCharOfStmt == 'S'), true, false);
797                        }
798 
799                        if (this.retrieveGeneratedKeys) {
800                                this.connection.setReadInfoMsgEnabled(oldInfoMsgState);
801                                rs.setFirstCharOfQuery('R');
802                        }
803 
804                        if (oldCatalog != null) {
805                                this.connection.setCatalog(oldCatalog);
806                        }
807 
808                        this.lastInsertId = rs.getUpdateID();
809 
810                        if (rs != null) {
811                                this.results = rs;
812                        }
813                }
814 
815                return ((rs != null) && rs.reallyResult());
816        }
817 
818        /**
819         * JDBC 2.0 Submit a batch of commands to the database for execution. This
820         * method is optional.
821         * 
822         * @return an array of update counts containing one element for each command
823         *         in the batch. The array is ordered according to the order in
824         *         which commands were inserted into the batch
825         * 
826         * @exception SQLException
827         *                if a database-access error occurs, or the driver does not
828         *                support batch statements
829         * @throws java.sql.BatchUpdateException
830         *             DOCUMENT ME!
831         */
832        public int[] executeBatch() throws SQLException {
833                if (this.connection.isReadOnly()) {
834                        throw new SQLException(Messages.getString("PreparedStatement.25") //$NON-NLS-1$
835                                        + Messages.getString("PreparedStatement.26"), //$NON-NLS-1$
836                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
837                }
838 
839                synchronized (this.connection.getMutex()) {
840                        try {
841                                clearWarnings();
842 
843                                if (!this.batchHasPlainStatements
844                                                && this.connection.getRewriteBatchedStatements()) {
845                                        if (StringUtils.startsWithIgnoreCaseAndWs(this.originalSql,
846                                                        "INSERT")) {
847                                                return executeBatchedInserts();
848                                        }
849                                }
850 
851                                return executeBatchSerially();
852                        } finally {
853                                clearBatch();
854                        }
855                }
856        }
857 
858        /**
859         * Rewrites the already prepared statement into a multi-value insert
860         * statement of 'statementsPerBatch' values and executes the entire batch
861         * using this new statement.
862         * 
863         * @return update counts in the same fashion as executeBatch()
864         * 
865         * @throws SQLException
866         */
867        private int[] executeBatchedInserts() throws SQLException {
868                String valuesClause = extractValuesClause();
869 
870                if (valuesClause == null) {
871                        return executeBatchSerially();
872                }
873 
874                int numBatchedArgs = this.batchedArgs.size();
875                
876                if (this.retrieveGeneratedKeys) {
877                        this.batchedGeneratedKeys = new ArrayList(numBatchedArgs);
878                }
879 
880                int numValuesPerBatch = computeBatchSize(numBatchedArgs);
881 
882                if (numBatchedArgs < numValuesPerBatch) {
883                        numValuesPerBatch = numBatchedArgs;
884                }
885 
886                java.sql.PreparedStatement batchedStatement = null;
887 
888                if (this.retrieveGeneratedKeys) {
889                        batchedStatement = this.connection.prepareStatement(
890                                        generateBatchedInsertSQL(valuesClause, numValuesPerBatch),
891                                        RETURN_GENERATED_KEYS);
892                } else {
893                        batchedStatement = this.connection
894                                        .prepareStatement(generateBatchedInsertSQL(valuesClause,
895                                                        numValuesPerBatch));
896                }
897 
898                int batchedParamIndex = 1;
899                int updateCountRunningTotal = 0;
900                int numberToExecuteAsMultiValue = 0;
901                int batchCounter = 0;
902 
903                if (numBatchedArgs < numValuesPerBatch) {
904                        numberToExecuteAsMultiValue = numBatchedArgs;
905                } else {
906                        numberToExecuteAsMultiValue = numBatchedArgs / numValuesPerBatch;
907                }
908 
909                int numberArgsToExecute = numberToExecuteAsMultiValue * numValuesPerBatch;
910 
911                for (int i = 0; i < numberArgsToExecute; i++) {
912                        if (i != 0 && i % numValuesPerBatch == 0) {
913                                updateCountRunningTotal += batchedStatement.executeUpdate();
914 
915                                getBatchedGeneratedKeys(batchedStatement);
916                                batchedStatement.clearParameters();
917                                batchedParamIndex = 1;
918 
919                        }
920 
921                        BatchParams paramArg = (BatchParams) this.batchedArgs
922                                        .get(batchCounter++);
923 
924                        batchedParamIndex = setOneBatchedParameterSet(batchedStatement,
925                                        batchedParamIndex, paramArg);
926                }
927 
928                updateCountRunningTotal += batchedStatement.executeUpdate();
929                getBatchedGeneratedKeys(batchedStatement);
930 
931                numValuesPerBatch = numBatchedArgs - batchCounter;
932 
933                if (numValuesPerBatch > 0) {
934 
935                        batchedStatement = this.connection.prepareStatement(
936                                        generateBatchedInsertSQL(valuesClause, numValuesPerBatch),
937                                        RETURN_GENERATED_KEYS);
938                        batchedParamIndex = 1;
939 
940                        while (batchCounter < numBatchedArgs) {
941 
942                                BatchParams paramArg = (BatchParams) this.batchedArgs
943                                                .get(batchCounter++);
944                                batchedParamIndex = setOneBatchedParameterSet(batchedStatement,
945                                                batchedParamIndex, paramArg);
946                        }
947 
948                        updateCountRunningTotal += batchedStatement.executeUpdate();
949                        getBatchedGeneratedKeys(batchedStatement);
950                }
951 
952                int[] updateCounts = new int[this.batchedArgs.size()];
953 
954                for (int i = 0; i < this.batchedArgs.size(); i++) {
955                        updateCounts[i] = 1;
956                }
957 
958                return updateCounts;
959        }
960 
961        protected int computeBatchSize(int numBatchedArgs) {
962                long sizeOfEntireBatch = 0;
963                long maxSizeOfParameterSet = 0;
964                
965                for (int i = 0; i < numBatchedArgs; i++) {
966                        BatchParams paramArg = (BatchParams) this.batchedArgs
967                        .get(i);
968 
969                        boolean[] isNullBatch = paramArg.isNull;
970                        boolean[] isStreamBatch = paramArg.isStream;
971 
972                        long sizeOfParameterSet = 0;
973                        
974                        for (int j = 0; j < isNullBatch.length; j++) {
975                                if (!isNullBatch[j]) {
976 
977                                        if (isStreamBatch[j]) {
978                                                int streamLength = paramArg.streamLengths[j];
979                                                
980                                                if (streamLength != -1) {
981                                                        sizeOfParameterSet += streamLength * 2; // for safety in escaping
982                                                } else {
983                                                        int paramLength = paramArg.parameterStrings[j].length;
984                                                        sizeOfParameterSet += paramLength;
985                                                }
986                                        } else {
987                                                sizeOfParameterSet += 4; // for NULL literal in SQL 
988                                        }
989                                }
990                        }
991                        
992                        //
993                        // Account for static part of values clause
994                        // This is a little naiive, because the ?s will be replaced
995                        // but it gives us some padding, and is less housekeeping
996                        // to ignore them. We're looking for a "fuzzy" value here
997                        // anyway
998                        //
999                        
1000                        sizeOfParameterSet += this.batchedValuesClause.length() + 1; 
1001                        sizeOfEntireBatch += sizeOfParameterSet;
1002                        
1003                        if (sizeOfParameterSet > maxSizeOfParameterSet) {
1004                                maxSizeOfParameterSet = sizeOfParameterSet;
1005                        }
1006                }
1007                
1008                int maxAllowedPacket = this.connection.getMaxAllowedPacket();
1009                
1010                if (sizeOfEntireBatch < maxAllowedPacket - this.originalSql.length()) {
1011                        return numBatchedArgs;
1012                }
1013                
1014                return (int)Math.max(1, (maxAllowedPacket - this.originalSql.length()) / maxSizeOfParameterSet);
1015        }
1016 
1017        /**
1018         * Executes the current batch of statements by executing them one-by-one.
1019         * 
1020         * @return a list of update counts
1021         * @throws SQLException
1022         *             if an error occurs
1023         */
1024        protected int[] executeBatchSerially() throws SQLException {
1025 
1026                int[] updateCounts = null;
1027 
1028                if (this.batchedArgs != null) {
1029                        int nbrCommands = this.batchedArgs.size();
1030                        updateCounts = new int[nbrCommands];
1031 
1032                        for (int i = 0; i < nbrCommands; i++) {
1033                                updateCounts[i] = -3;
1034                        }
1035 
1036                        SQLException sqlEx = null;
1037 
1038                        int commandIndex = 0;
1039 
1040                        if (this.retrieveGeneratedKeys) {
1041                                this.batchedGeneratedKeys = new ArrayList(nbrCommands);
1042                        }
1043 
1044                        for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
1045                                Object arg = this.batchedArgs.get(commandIndex);
1046 
1047                                if (arg instanceof String) {
1048                                        updateCounts[commandIndex] = executeUpdate((String) arg);
1049                                } else {
1050                                        BatchParams paramArg = (BatchParams) arg;
1051 
1052                                        try {
1053                                                updateCounts[commandIndex] = executeUpdate(
1054                                                                paramArg.parameterStrings,
1055                                                                paramArg.parameterStreams, paramArg.isStream,
1056                                                                paramArg.streamLengths, paramArg.isNull, true);
1057 
1058                                                if (this.retrieveGeneratedKeys) {
1059                                                        java.sql.ResultSet rs = null;
1060 
1061                                                        try {
1062                                                                rs = getGeneratedKeysInternal();
1063 
1064                                                                while (rs.next()) {
1065                                                                        this.batchedGeneratedKeys
1066                                                                                        .add(new byte[][] { rs.getBytes(1) });
1067                                                                }
1068                                                        } finally {
1069                                                                if (rs != null) {
1070                                                                        rs.close();
1071                                                                }
1072                                                        }
1073                                                }
1074                                        } catch (SQLException ex) {
1075                                                updateCounts[commandIndex] = EXECUTE_FAILED;
1076 
1077                                                if (this.connection.getContinueBatchOnError()) {
1078                                                        sqlEx = ex;
1079                                                } else {
1080                                                        int[] newUpdateCounts = new int[commandIndex];
1081                                                        System.arraycopy(updateCounts, 0, newUpdateCounts,
1082                                                                        0, commandIndex);
1083 
1084                                                        throw new java.sql.BatchUpdateException(ex
1085                                                                        .getMessage(), ex.getSQLState(), ex
1086                                                                        .getErrorCode(), newUpdateCounts);
1087                                                }
1088                                        }
1089                                }
1090                        }
1091 
1092                        if (sqlEx != null) {
1093                                throw new java.sql.BatchUpdateException(sqlEx.getMessage(),
1094                                                sqlEx.getSQLState(), sqlEx.getErrorCode(), updateCounts);
1095                        }
1096                }
1097 
1098                return (updateCounts != null) ? updateCounts : new int[0];
1099        }
1100 
1101        /**
1102         * Actually execute the prepared statement. This is here so server-side
1103         * PreparedStatements can re-use most of the code from this class.
1104         * 
1105         * @param maxRowsToRetrieve
1106         *            the max number of rows to return
1107         * @param sendPacket
1108         *            the packet to send
1109         * @param createStreamingResultSet
1110         *            should a 'streaming' result set be created?
1111         * @param queryIsSelectOnly
1112         *            is this query doing a SELECT?
1113         * @param unpackFields
1114         *            DOCUMENT ME!
1115         * 
1116         * @return the results as a ResultSet
1117         * 
1118         * @throws SQLException
1119         *             if an error occurs.
1120         */
1121        protected ResultSet executeInternal(int maxRowsToRetrieve,
1122                        Buffer sendPacket, boolean createStreamingResultSet,
1123                        boolean queryIsSelectOnly, boolean unpackFields, boolean isBatch)
1124                        throws SQLException {
1125                this.numberOfExecutions++;
1126 
1127                ResultSet rs;
1128                rs = this.connection.execSQL(this, null, maxRowsToRetrieve, sendPacket,
1129                                this.resultSetType, this.resultSetConcurrency,
1130                                createStreamingResultSet, false, this.currentCatalog,
1131                                unpackFields, USES_VARIABLES_UNKNOWN, isBatch);
1132 
1133                return rs;
1134        }
1135 
1136        /**
1137         * A Prepared SQL query is executed and its ResultSet is returned
1138         * 
1139         * @return a ResultSet that contains the data produced by the query - never
1140         *         null
1141         * 
1142         * @exception SQLException
1143         *                if a database access error occurs
1144         */
1145        public synchronized java.sql.ResultSet executeQuery() throws SQLException {
1146                checkClosed();
1147 
1148                checkForDml(this.originalSql, this.firstCharOfStmt);
1149 
1150                CachedResultSetMetaData cachedMetadata = null;
1151 
1152                // We need to execute this all together
1153                // So synchronize on the Connection's mutex (because
1154                // even queries going through there synchronize
1155                // on the same mutex.
1156                synchronized (this.connection.getMutex()) {
1157                        clearWarnings();
1158 
1159                        this.batchedGeneratedKeys = null;
1160 
1161                        Buffer sendPacket = fillSendPacket();
1162 
1163                        if (this.results != null) {
1164                                if (!this.connection.getHoldResultsOpenOverStatementClose()) {
1165                                        this.results.realClose(false);
1166                                }
1167                        }
1168 
1169                        String oldCatalog = null;
1170 
1171                        if (!this.connection.getCatalog().equals(this.currentCatalog)) {
1172                                oldCatalog = this.connection.getCatalog();
1173                                this.connection.setCatalog(this.currentCatalog);
1174                        }
1175 
1176                        //
1177                        // Check if we have cached metadata for this query...
1178                        //
1179                        if (this.connection.getCacheResultSetMetadata()) {
1180                                cachedMetadata = getCachedMetaData(this.originalSql);
1181                        }
1182 
1183                        if (this.connection.useMaxRows()) {
1184                                // If there isn't a limit clause in the SQL
1185                                // then limit the number of rows to return in
1186                                // an efficient manner. Only do this if
1187                                // setMaxRows() hasn't been used on any Statements
1188                                // generated from the current Connection (saves
1189                                // a query, and network traffic).
1190                                if (this.hasLimitClause) {
1191                                        this.results = executeInternal(this.maxRows, sendPacket,
1192                                                        createStreamingResultSet(), true,
1193                                                        (cachedMetadata == null), false);
1194                                } else {
1195                                        if (this.maxRows <= 0) {
1196                                                this.connection
1197                                                                .execSQL(
1198                                                                                this,
1199                                                                                "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
1200                                                                                java.sql.ResultSet.TYPE_FORWARD_ONLY,
1201                                                                                java.sql.ResultSet.CONCUR_READ_ONLY,
1202                                                                                false, false, this.currentCatalog, true);
1203                                        } else {
1204                                                this.connection
1205                                                                .execSQL(
1206                                                                                this,
1207                                                                                "SET OPTION SQL_SELECT_LIMIT=" + this.maxRows, -1, null, //$NON-NLS-1$
1208                                                                                java.sql.ResultSet.TYPE_FORWARD_ONLY,
1209                                                                                java.sql.ResultSet.CONCUR_READ_ONLY,
1210                                                                                false, false, this.currentCatalog, true);
1211                                        }
1212 
1213                                        this.results = executeInternal(-1, sendPacket,
1214                                                        createStreamingResultSet(), true,
1215                                                        (cachedMetadata == null), false);
1216 
1217                                        if (oldCatalog != null) {
1218                                                this.connection.setCatalog(oldCatalog);
1219                                        }
1220                                }
1221                        } else {
1222                                this.results = executeInternal(-1, sendPacket,
1223                                                createStreamingResultSet(), true,
1224                                                (cachedMetadata == null), false);
1225                        }
1226 
1227                        if (oldCatalog != null) {
1228                                this.connection.setCatalog(oldCatalog);
1229                        }
1230                }
1231 
1232                this.lastInsertId = this.results.getUpdateID();
1233 
1234                if (cachedMetadata != null) {
1235                        initializeResultsMetadataFromCache(this.originalSql,
1236                                        cachedMetadata, this.results);
1237                } else {
1238                        if (this.connection.getCacheResultSetMetadata()) {
1239                                initializeResultsMetadataFromCache(this.originalSql,
1240                                                null /* will be created */, this.results);
1241                        }
1242                }
1243 
1244                return this.results;
1245        }
1246 
1247        /**
1248         * Execute a SQL INSERT, UPDATE or DELETE statement. In addition, SQL
1249         * statements that return nothing such as SQL DDL statements can be
1250         * executed.
1251         * 
1252         * @return either the row count for INSERT, UPDATE or DELETE; or 0 for SQL
1253         *         statements that return nothing.
1254         * 
1255         * @exception SQLException
1256         *                if a database access error occurs
1257         */
1258        public synchronized int executeUpdate() throws SQLException {
1259                return executeUpdate(true);
1260        }
1261 
1262        /*
1263         * We need this variant, because ServerPreparedStatement calls this for
1264         * batched updates, which will end up clobbering the warnings and generated
1265         * keys we need to gather for the batch.
1266         */
1267        protected synchronized int executeUpdate(
1268                        boolean clearBatchedGeneratedKeysAndWarnings) throws SQLException {
1269                if (clearBatchedGeneratedKeysAndWarnings) {
1270                        clearWarnings();
1271                        this.batchedGeneratedKeys = null;
1272                }
1273 
1274                return executeUpdate(this.parameterValues, this.parameterStreams,
1275                                this.isStream, this.streamLengths, this.isNull, false);
1276        }
1277 
1278        /**
1279         * Added to allow batch-updates
1280         * 
1281         * @param batchedParameterStrings
1282         *            string values used in single statement
1283         * @param batchedParameterStreams
1284         *            stream values used in single statement
1285         * @param batchedIsStream
1286         *            flags for streams used in single statement
1287         * @param batchedStreamLengths
1288         *            lengths of streams to be read.
1289         * @param batchedIsNull
1290         *            flags for parameters that are null
1291         * 
1292         * @return the update count
1293         * 
1294         * @throws SQLException
1295         *             if a database error occurs
1296         */
1297        protected synchronized int executeUpdate(byte[][] batchedParameterStrings,
1298                        InputStream[] batchedParameterStreams, boolean[] batchedIsStream,
1299                        int[] batchedStreamLengths, boolean[] batchedIsNull,
1300                        boolean isReallyBatch) throws SQLException {
1301                if (this.connection.isReadOnly()) {
1302                        throw new SQLException(Messages.getString("PreparedStatement.34") //$NON-NLS-1$
1303                                        + Messages.getString("PreparedStatement.35"), //$NON-NLS-1$
1304                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1305                }
1306 
1307                checkClosed();
1308 
1309                if ((this.firstCharOfStmt == 'S')
1310                                && StringUtils.startsWithIgnoreCaseAndWs(this.originalSql,
1311                                                "SELECT")) { //$NON-NLS-1$
1312                        throw new SQLException(Messages.getString("PreparedStatement.37"), //$NON-NLS-1$
1313                                        "01S03"); //$NON-NLS-1$
1314                }
1315 
1316                if (this.results != null) {
1317                        if (!this.connection.getHoldResultsOpenOverStatementClose()) {
1318                                this.results.realClose(false);
1319                        }
1320                }
1321 
1322                ResultSet rs = null;
1323 
1324                // The checking and changing of catalogs
1325                // must happen in sequence, so synchronize
1326                // on the same mutex that _conn is using
1327                synchronized (this.connection.getMutex()) {
1328                        Buffer sendPacket = fillSendPacket(batchedParameterStrings,
1329                                        batchedParameterStreams, batchedIsStream,
1330                                        batchedStreamLengths);
1331 
1332                        String oldCatalog = null;
1333 
1334                        if (!this.connection.getCatalog().equals(this.currentCatalog)) {
1335                                oldCatalog = this.connection.getCatalog();
1336                                this.connection.setCatalog(this.currentCatalog);
1337                        }
1338 
1339                        //
1340                        // Only apply max_rows to selects
1341                        //
1342                        if (this.connection.useMaxRows()) {
1343                                this.connection.execSQL(this,
1344                                                "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
1345                                                java.sql.ResultSet.TYPE_FORWARD_ONLY,
1346                                                java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
1347                                                this.currentCatalog, true);
1348                        }
1349 
1350                        boolean oldInfoMsgState = false;
1351 
1352                        if (this.retrieveGeneratedKeys) {
1353                                oldInfoMsgState = this.connection.isReadInfoMsgEnabled();
1354                                this.connection.setReadInfoMsgEnabled(true);
1355                        }
1356 
1357                        rs = executeInternal(-1, sendPacket, false, false, true,
1358                                        isReallyBatch);
1359 
1360                        if (this.retrieveGeneratedKeys) {
1361                                this.connection.setReadInfoMsgEnabled(oldInfoMsgState);
1362                                rs.setFirstCharOfQuery(this.firstCharOfStmt);
1363                        }
1364 
1365                        if (oldCatalog != null) {
1366                                this.connection.setCatalog(oldCatalog);
1367                        }
1368                }
1369 
1370                this.results = rs;
1371 
1372                this.updateCount = rs.getUpdateCount();
1373 
1374                int truncatedUpdateCount = 0;
1375 
1376                if (this.updateCount > Integer.MAX_VALUE) {
1377                        truncatedUpdateCount = Integer.MAX_VALUE;
1378                } else {
1379                        truncatedUpdateCount = (int) this.updateCount;
1380                }
1381 
1382                this.lastInsertId = rs.getUpdateID();
1383 
1384                return truncatedUpdateCount;
1385        }
1386 
1387        private synchronized String extractValuesClause() throws SQLException {
1388                if (this.batchedValuesClause == null) {
1389                        String quoteCharStr = this.connection.getMetaData()
1390                                        .getIdentifierQuoteString();
1391        
1392                        int indexOfValues = -1;
1393        
1394                        if (quoteCharStr.length() > 0) {
1395                                indexOfValues = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
1396                                                this.originalSql, "VALUES ", quoteCharStr.charAt(0), false);
1397                        } else {
1398                                indexOfValues = StringUtils.indexOfIgnoreCase(0, this.originalSql,
1399                                                "VALUES ");
1400                        }
1401        
1402                        if (indexOfValues == -1) {
1403                                return null;
1404                        }
1405        
1406                        int indexOfFirstParen = this.originalSql
1407                                        .indexOf('(', indexOfValues + 7);
1408        
1409                        if (indexOfFirstParen == -1) {
1410                                return null;
1411                        }
1412        
1413                        int indexOfLastParen = this.originalSql.lastIndexOf(')');
1414        
1415                        if (indexOfLastParen == -1) {
1416                                return null;
1417                        }
1418        
1419                        this.batchedValuesClause = this.originalSql.substring(indexOfFirstParen,
1420                                        indexOfLastParen + 1);
1421                }
1422                        
1423                return this.batchedValuesClause;
1424        }
1425 
1426        /**
1427         * Creates the packet that contains the query to be sent to the server.
1428         * 
1429         * @return A Buffer filled with the query representing the
1430         *         PreparedStatement.
1431         * 
1432         * @throws SQLException
1433         *             if an error occurs.
1434         */
1435        protected Buffer fillSendPacket() throws SQLException {
1436                return fillSendPacket(this.parameterValues, this.parameterStreams,
1437                                this.isStream, this.streamLengths);
1438        }
1439 
1440        /**
1441         * Creates the packet that contains the query to be sent to the server.
1442         * 
1443         * @param batchedParameterStrings
1444         *            the parameters as strings
1445         * @param batchedParameterStreams
1446         *            the parameters as streams
1447         * @param batchedIsStream
1448         *            is the given parameter a stream?
1449         * @param batchedStreamLengths
1450         *            the lengths of the streams (if appropriate)
1451         * 
1452         * @return a Buffer filled with the query that represents this statement
1453         * 
1454         * @throws SQLException
1455         *             if an error occurs.
1456         */
1457        protected Buffer fillSendPacket(byte[][] batchedParameterStrings,
1458                        InputStream[] batchedParameterStreams, boolean[] batchedIsStream,
1459                        int[] batchedStreamLengths) throws SQLException {
1460                Buffer sendPacket = this.connection.getIO().getSharedSendPacket();
1461 
1462                sendPacket.clear();
1463 
1464                sendPacket.writeByte((byte) MysqlDefs.QUERY);
1465 
1466                boolean useStreamLengths = this.connection
1467                                .getUseStreamLengthsInPrepStmts();
1468 
1469                //
1470                // Try and get this allocation as close as possible
1471                // for BLOBs
1472                //
1473                int ensurePacketSize = 0;
1474 
1475                for (int i = 0; i < batchedParameterStrings.length; i++) {
1476                        if (batchedIsStream[i] && useStreamLengths) {
1477                                ensurePacketSize += batchedStreamLengths[i];
1478                        }
1479                }
1480 
1481                if (ensurePacketSize != 0) {
1482                        sendPacket.ensureCapacity(ensurePacketSize);
1483                }
1484 
1485                for (int i = 0; i < batchedParameterStrings.length; i++) {
1486                        if ((batchedParameterStrings[i] == null)
1487                                        && (batchedParameterStreams[i] == null)) {
1488                                throw new SQLException(Messages
1489                                                .getString("PreparedStatement.40") //$NON-NLS-1$
1490                                                + (i + 1), SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS);
1491                        }
1492 
1493                        sendPacket.writeBytesNoNull(this.staticSqlStrings[i]);
1494 
1495                        if (batchedIsStream[i]) {
1496                                streamToBytes(sendPacket, batchedParameterStreams[i], true,
1497                                                batchedStreamLengths[i], useStreamLengths);
1498                        } else {
1499                                sendPacket.writeBytesNoNull(batchedParameterStrings[i]);
1500                        }
1501                }
1502 
1503                sendPacket
1504                                .writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]);
1505 
1506                return sendPacket;
1507        }
1508 
1509        private String generateBatchedInsertSQL(String valuesClause, int numBatches) {
1510                StringBuffer newStatementSql = new StringBuffer(this.originalSql
1511                                .length()
1512                                + (numBatches * (valuesClause.length() + 1)));
1513 
1514                newStatementSql.append(this.originalSql);
1515 
1516                for (int i = 0; i < numBatches - 1; i++) {
1517                        newStatementSql.append(',');
1518                        newStatementSql.append(valuesClause);
1519                }
1520 
1521                return newStatementSql.toString();
1522        }
1523 
1524        /**
1525         * DOCUMENT ME!
1526         * 
1527         * @param parameterIndex
1528         *            DOCUMENT ME!
1529         * 
1530         * @return DOCUMENT ME!
1531         * 
1532         * @throws SQLException
1533         *             DOCUMENT ME!
1534         */
1535        public byte[] getBytesRepresentation(int parameterIndex)
1536                        throws SQLException {
1537                if (this.isStream[parameterIndex]) {
1538                        return streamToBytes(this.parameterStreams[parameterIndex], false,
1539                                        this.streamLengths[parameterIndex], this.connection
1540                                                        .getUseStreamLengthsInPrepStmts());
1541                }
1542 
1543                byte[] parameterVal = this.parameterValues[parameterIndex];
1544 
1545                if (parameterVal == null) {
1546                        return null;
1547                }
1548 
1549                if ((parameterVal[0] == '\'')
1550                                && (parameterVal[parameterVal.length - 1] == '\'')) {
1551                        byte[] valNoQuotes = new byte[parameterVal.length - 2];
1552                        System.arraycopy(parameterVal, 1, valNoQuotes, 0,
1553                                        parameterVal.length - 2);
1554 
1555                        return valNoQuotes;
1556                }
1557 
1558                return parameterVal;
1559        }
1560 
1561        private final String getDateTimePattern(String dt, boolean toTime)
1562                        throws Exception {
1563                //
1564                // Special case
1565                //
1566                int dtLength = (dt != null) ? dt.length() : 0;
1567 
1568                if ((dtLength >= 8) && (dtLength <= 10)) {
1569                        int dashCount = 0;
1570                        boolean isDateOnly = true;
1571 
1572                        for (int i = 0; i < dtLength; i++) {
1573                                char c = dt.charAt(i);
1574 
1575                                if (!Character.isDigit(c) && (c != '-')) {
1576                                        isDateOnly = false;
1577 
1578                                        break;
1579                                }
1580 
1581                                if (c == '-') {
1582                                        dashCount++;
1583                                }
1584                        }
1585 
1586                        if (isDateOnly && (dashCount == 2)) {
1587                                return "yyyy-MM-dd"; //$NON-NLS-1$
1588                        }
1589                }
1590 
1591                //
1592                // Special case - time-only
1593                //
1594                boolean colonsOnly = true;
1595 
1596                for (int i = 0; i < dtLength; i++) {
1597                        char c = dt.charAt(i);
1598 
1599                        if (!Character.isDigit(c) && (c != ':')) {
1600                                colonsOnly = false;
1601 
1602                                break;
1603                        }
1604                }
1605 
1606                if (colonsOnly) {
1607                        return "HH:mm:ss"; //$NON-NLS-1$
1608                }
1609 
1610                int n;
1611                int z;
1612                int count;
1613                int maxvecs;
1614                char c;
1615                char separator;
1616                StringReader reader = new StringReader(dt + " "); //$NON-NLS-1$
1617                ArrayList vec = new ArrayList();
1618                ArrayList vecRemovelist = new ArrayList();
1619                Object[] nv = new Object[3];
1620                Object[] v;
1621                nv[0] = new Character('y');
1622                nv[1] = new StringBuffer();
1623                nv[2] = new Integer(0);
1624                vec.add(nv);
1625 
1626                if (toTime) {
1627                        nv = new Object[3];
1628                        nv[0] = new Character('h');
1629                        nv[1] = new StringBuffer();
1630                        nv[2] = new Integer(0);
1631                        vec.add(nv);
1632                }
1633 
1634                while ((z = reader.read()) != -1) {
1635                        separator = (char) z;
1636                        maxvecs = vec.size();
1637 
1638                        for (count = 0; count < maxvecs; count++) {
1639                                v = (Object[]) vec.get(count);
1640                                n = ((Integer) v[2]).intValue();
1641                                c = getSuccessor(((Character) v[0]).charValue(), n);
1642 
1643                                if (!Character.isLetterOrDigit(separator)) {
1644                                        if ((c == ((Character) v[0]).charValue()) && (c != 'S')) {
1645                                                vecRemovelist.add(v);
1646                                        } else {
1647                                                ((StringBuffer) v[1]).append(separator);
1648 
1649                                                if ((c == 'X') || (c == 'Y')) {
1650                                                        v[2] = new Integer(4);
1651                                                }
1652                                        }
1653                                } else {
1654                                        if (c == 'X') {
1655                                                c = 'y';
1656                                                nv = new Object[3];
1657                                                nv[1] = (new StringBuffer(((StringBuffer) v[1])
1658                                                                .toString())).append('M');
1659                                                nv[0] = new Character('M');
1660                                                nv[2] = new Integer(1);
1661                                                vec.add(nv);
1662                                        } else if (c == 'Y') {
1663                                                c = 'M';
1664                                                nv = new Object[3];
1665                                                nv[1] = (new StringBuffer(((StringBuffer) v[1])
1666                                                                .toString())).append('d');
1667                                                nv[0] = new Character('d');
1668                                                nv[2] = new Integer(1);
1669                                                vec.add(nv);
1670                                        }
1671 
1672                                        ((StringBuffer) v[1]).append(c);
1673 
1674                                        if (c == ((Character) v[0]).charValue()) {
1675                                                v[2] = new Integer(n + 1);
1676                                        } else {
1677                                                v[0] = new Character(c);
1678                                                v[2] = new Integer(1);
1679                                        }
1680                                }
1681                        }
1682 
1683                        int size = vecRemovelist.size();
1684 
1685                        for (int i = 0; i < size; i++) {
1686                                v = (Object[]) vecRemovelist.get(i);
1687                                vec.remove(v);
1688                        }
1689 
1690                        vecRemovelist.clear();
1691                }
1692 
1693                int size = vec.size();
1694 
1695                for (int i = 0; i < size; i++) {
1696                        v = (Object[]) vec.get(i);
1697                        c = ((Character) v[0]).charValue();
1698                        n = ((Integer) v[2]).intValue();
1699 
1700                        boolean bk = getSuccessor(c, n) != c;
1701                        boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk);
1702                        boolean finishesAtDate = (bk && (c == 'd') && !toTime);
1703                        boolean containsEnd = (((StringBuffer) v[1]).toString()
1704                                        .indexOf('W') != -1);
1705 
1706                        if ((!atEnd && !finishesAtDate) || (containsEnd)) {
1707                                vecRemovelist.add(v);
1708                        }
1709                }
1710 
1711                size = vecRemovelist.size();
1712 
1713                for (int i = 0; i < size; i++) {
1714                        vec.remove(vecRemovelist.get(i));
1715                }
1716 
1717                vecRemovelist.clear();
1718                v = (Object[]) vec.get(0); // might throw exception
1719 
1720                StringBuffer format = (StringBuffer) v[1];
1721                format.setLength(format.length() - 1);
1722 
1723                return format.toString();
1724        }
1725 
1726        /**
1727         * The number, types and properties of a ResultSet's columns are provided by
1728         * the getMetaData method.
1729         * 
1730         * @return the description of a ResultSet's columns
1731         * 
1732         * @exception SQLException
1733         *                if a database-access error occurs.
1734         */
1735        public synchronized java.sql.ResultSetMetaData getMetaData()
1736                        throws SQLException {
1737 
1738                if (!StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(
1739                                this.originalSql, "SELECT")) {
1740                        return null;
1741                }
1742 
1743                PreparedStatement mdStmt = null;
1744                java.sql.ResultSet mdRs = null;
1745 
1746                if (this.pstmtResultMetaData == null) {
1747                        try {
1748                                mdStmt = new PreparedStatement(this.connection,
1749                                                this.originalSql, this.currentCatalog, this.parseInfo);
1750 
1751                                mdStmt.setMaxRows(0);
1752 
1753                                int paramCount = this.parameterValues.length;
1754 
1755                                for (int i = 1; i <= paramCount; i++) {
1756                                        mdStmt.setString(i, ""); //$NON-NLS-1$
1757                                }
1758 
1759                                boolean hadResults = mdStmt.execute();
1760 
1761                                if (hadResults) {
1762                                        mdRs = mdStmt.getResultSet();
1763 
1764                                        this.pstmtResultMetaData = mdRs.getMetaData();
1765                                } else {
1766                                        this.pstmtResultMetaData = new ResultSetMetaData(
1767                                                        new Field[0]);
1768                                }
1769                        } finally {
1770                                SQLException sqlExRethrow = null;
1771 
1772                                if (mdRs != null) {
1773                                        try {
1774                                                mdRs.close();
1775                                        } catch (SQLException sqlEx) {
1776                                                sqlExRethrow = sqlEx;
1777                                        }
1778 
1779                                        mdRs = null;
1780                                }
1781 
1782                                if (mdStmt != null) {
1783                                        try {
1784                                                mdStmt.close();
1785                                        } catch (SQLException sqlEx) {
1786                                                sqlExRethrow = sqlEx;
1787                                        }
1788 
1789                                        mdStmt = null;
1790                                }
1791 
1792                                if (sqlExRethrow != null) {
1793                                        throw sqlExRethrow;
1794                                }
1795                        }
1796                }
1797 
1798                return this.pstmtResultMetaData;
1799        }
1800 
1801        /**
1802         * @see PreparedStatement#getParameterMetaData()
1803         */
1804        public synchronized ParameterMetaData getParameterMetaData()
1805                        throws SQLException {
1806                if (this.parameterMetaData == null) {
1807                        this.parameterMetaData = new MysqlParameterMetadata(null,
1808                                        this.parameterCount);
1809                }
1810 
1811                return this.parameterMetaData;
1812        }
1813 
1814        ParseInfo getParseInfo() {
1815                return this.parseInfo;
1816        }
1817 
1818        private final char getSuccessor(char c, int n) {
1819                return ((c == 'y') && (n == 2)) ? 'X'
1820                                : (((c == 'y') && (n < 4)) ? 'y'
1821                                                : ((c == 'y') ? 'M'
1822                                                                : (((c == 'M') && (n == 2)) ? 'Y'
1823                                                                                : (((c == 'M') && (n < 3)) ? 'M'
1824                                                                                                : ((c == 'M') ? 'd'
1825                                                                                                                : (((c == 'd') && (n < 2)) ? 'd'
1826                                                                                                                                : ((c == 'd') ? 'H'
1827                                                                                                                                                : (((c == 'H') && (n < 2)) ? 'H'
1828                                                                                                                                                                : ((c == 'H') ? 'm'
1829                                                                                                                                                                                : (((c == 'm') && (n < 2)) ? 'm'
1830                                                                                                                                                                                                : ((c == 'm') ? 's'
1831                                                                                                                                                                                                                : (((c == 's') && (n < 2)) ? 's'
1832                                                                                                                                                                                                                                : 'W'))))))))))));
1833        }
1834 
1835        /**
1836         * Used to escape binary data with hex for mb charsets
1837         * 
1838         * @param buf
1839         * @param packet
1840         * @param size
1841         * @throws SQLException
1842         */
1843        private final void hexEscapeBlock(byte[] buf, Buffer packet, int size)
1844                        throws SQLException {
1845                for (int i = 0; i < size; i++) {
1846                        byte b = buf[i];
1847                        int lowBits = (b & 0xff) / 16;
1848                        int highBits = (b & 0xff) % 16;
1849 
1850                        packet.writeByte(HEX_DIGITS[lowBits]);
1851                        packet.writeByte(HEX_DIGITS[highBits]);
1852                }
1853        }
1854 
1855        private void initializeFromParseInfo() throws SQLException {
1856                this.staticSqlStrings = this.parseInfo.staticSql;
1857                this.hasLimitClause = this.parseInfo.foundLimitClause;
1858                this.isLoadDataQuery = this.parseInfo.foundLoadData;
1859                this.firstCharOfStmt = this.parseInfo.firstStmtChar;
1860 
1861                this.parameterCount = this.staticSqlStrings.length - 1;
1862 
1863                this.parameterValues = new byte[this.parameterCount][];
1864                this.parameterStreams = new InputStream[this.parameterCount];
1865                this.isStream = new boolean[this.parameterCount];
1866                this.streamLengths = new int[this.parameterCount];
1867                this.isNull = new boolean[this.parameterCount];
1868 
1869                clearParameters();
1870 
1871                for (int j = 0; j < this.parameterCount; j++) {
1872                        this.isStream[j] = false;
1873                }
1874        }
1875 
1876        boolean isNull(int paramIndex) {
1877                return this.isNull[paramIndex];
1878        }
1879 
1880        private final int readblock(InputStream i, byte[] b) throws SQLException {
1881                try {
1882                        return i.read(b);
1883                } catch (Throwable E) {
1884                        throw new SQLException(Messages.getString("PreparedStatement.56") //$NON-NLS-1$
1885                                        + E.getClass().getName(), SQLError.SQL_STATE_GENERAL_ERROR);
1886                }
1887        }
1888 
1889        private final int readblock(InputStream i, byte[] b, int length)
1890                        throws SQLException {
1891                try {
1892                        int lengthToRead = length;
1893 
1894                        if (lengthToRead > b.length) {
1895                                lengthToRead = b.length;
1896                        }
1897 
1898                        return i.read(b, 0, lengthToRead);
1899                } catch (Throwable E) {
1900                        throw new SQLException(Messages.getString("PreparedStatement.55") //$NON-NLS-1$
1901                                        + E.getClass().getName(), SQLError.SQL_STATE_GENERAL_ERROR);
1902                }
1903        }
1904 
1905        /**
1906         * Closes this statement, releasing all resources
1907         * 
1908         * @param calledExplicitly
1909         *            was this called by close()?
1910         * 
1911         * @throws SQLException
1912         *             if an error occurs
1913         */
1914        protected void realClose(boolean calledExplicitly) throws SQLException {
1915                if (this.useUsageAdvisor) {
1916                        if (this.numberOfExecutions <= 1) {
1917                                String message = Messages.getString("PreparedStatement.43"); //$NON-NLS-1$
1918 
1919                                this.eventSink.consumeEvent(new ProfilerEvent(
1920                                                ProfilerEvent.TYPE_WARN, "", this.currentCatalog, //$NON-NLS-1$
1921                                                this.connection.getId(), this.getId(), -1, System
1922                                                                .currentTimeMillis(), 0, null,
1923                                                this.pointOfOrigin, message));
1924                        }
1925                }
1926 
1927                super.realClose(calledExplicitly);
1928 
1929                this.dbmd = null;
1930                this.originalSql = null;
1931                this.staticSqlStrings = null;
1932                this.parameterValues = null;
1933                this.parameterStreams = null;
1934                this.isStream = null;
1935                this.streamLengths = null;
1936                this.isNull = null;
1937                this.streamConvertBuf = null;
1938        }
1939 
1940        /**
1941         * JDBC 2.0 Set an Array parameter.
1942         * 
1943         * @param i
1944         *            the first parameter is 1, the second is 2, ...
1945         * @param x
1946         *            an object representing an SQL array
1947         * 
1948         * @throws SQLException
1949         *             because this method is not implemented.
1950         * @throws NotImplemented
1951         *             DOCUMENT ME!
1952         */
1953        public void setArray(int i, Array x) throws SQLException {
1954                throw new NotImplemented();
1955        }
1956 
1957        /**
1958         * When a very large ASCII value is input to a LONGVARCHAR parameter, it may
1959         * be more practical to send it via a java.io.InputStream. JDBC will read
1960         * the data from the stream as needed, until it reaches end-of-file. The
1961         * JDBC driver will do any necessary conversion from ASCII to the database
1962         * char format.
1963         * 
1964         * <P>
1965         * <B>Note:</B> This stream object can either be a standard Java stream
1966         * object or your own subclass that implements the standard interface.
1967         * </p>
1968         * 
1969         * @param parameterIndex
1970         *            the first parameter is 1...
1971         * @param x
1972         *            the parameter value
1973         * @param length
1974         *            the number of bytes in the stream
1975         * 
1976         * @exception SQLException
1977         *                if a database access error occurs
1978         */
1979        public synchronized void setAsciiStream(int parameterIndex, InputStream x,
1980                        int length) throws SQLException {
1981                if (x == null) {
1982                        setNull(parameterIndex, java.sql.Types.VARCHAR);
1983                } else {
1984                        setBinaryStream(parameterIndex, x, length);
1985                }
1986        }
1987 
1988        /**
1989         * Set a parameter to a java.math.BigDecimal value. The driver converts this
1990         * to a SQL NUMERIC value when it sends it to the database.
1991         * 
1992         * @param parameterIndex
1993         *            the first parameter is 1...
1994         * @param x
1995         *            the parameter value
1996         * 
1997         * @exception SQLException
1998         *                if a database access error occurs
1999         */
2000        public void setBigDecimal(int parameterIndex, BigDecimal x)
2001                        throws SQLException {
2002                if (x == null) {
2003                        setNull(parameterIndex, java.sql.Types.DECIMAL);
2004                } else {
2005                        setInternal(parameterIndex, StringUtils
2006                                        .fixDecimalExponent(StringUtils.consistentToString(x)));
2007                }
2008        }
2009 
2010        /**
2011         * When a very large binary value is input to a LONGVARBINARY parameter, it
2012         * may be more practical to send it via a java.io.InputStream. JDBC will
2013         * read the data from the stream as needed, until it reaches end-of-file.
2014         * 
2015         * <P>
2016         * <B>Note:</B> This stream object can either be a standard Java stream
2017         * object or your own subclass that implements the standard interface.
2018         * </p>
2019         * 
2020         * @param parameterIndex
2021         *            the first parameter is 1...
2022         * @param x
2023         *            the parameter value
2024         * @param length
2025         *            the number of bytes to read from the stream (ignored)
2026         * 
2027         * @throws SQLException
2028         *             if a database access error occurs
2029         */
2030        public void setBinaryStream(int parameterIndex, InputStream x, int length)
2031                        throws SQLException {
2032                if (x == null) {
2033                        setNull(parameterIndex, java.sql.Types.BINARY);
2034                } else {
2035                        if ((parameterIndex < 1)
2036                                        || (parameterIndex > this.staticSqlStrings.length)) {
2037                                throw new SQLException(
2038                                                Messages.getString("PreparedStatement.2") //$NON-NLS-1$
2039                                                                + parameterIndex
2040                                                                + Messages.getString("PreparedStatement.3") + this.staticSqlStrings.length + Messages.getString("PreparedStatement.4"), //$NON-NLS-1$ //$NON-NLS-2$
2041                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2042                        }
2043 
2044                        this.parameterStreams[parameterIndex - 1] = x;
2045                        this.isStream[parameterIndex - 1] = true;
2046                        this.streamLengths[parameterIndex - 1] = length;
2047                        this.isNull[parameterIndex - 1] = false;
2048                }
2049        }
2050 
2051        /**
2052         * JDBC 2.0 Set a BLOB parameter.
2053         * 
2054         * @param i
2055         *            the first parameter is 1, the second is 2, ...
2056         * @param x
2057         *            an object representing a BLOB
2058         * 
2059         * @throws SQLException
2060         *             if a database error occurs
2061         */
2062        public void setBlob(int i, java.sql.Blob x) throws SQLException {
2063                if (x == null) {
2064                        setNull(i, Types.BLOB);
2065                } else {
2066                        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
2067 
2068                        bytesOut.write('\'');
2069                        escapeblockFast(x.getBytes(1, (int) x.length()), bytesOut, (int) x
2070                                        .length());
2071                        bytesOut.write('\'');
2072 
2073                        setInternal(i, bytesOut.toByteArray());
2074                }
2075        }
2076 
2077        /**
2078         * Set a parameter to a Java boolean value. The driver converts this to a
2079         * SQL BIT value when it sends it to the database.
2080         * 
2081         * @param parameterIndex
2082         *            the first parameter is 1...
2083         * @param x
2084         *            the parameter value
2085         * 
2086         * @throws SQLException
2087         *             if a database access error occurs
2088         */
2089        public void setBoolean(int parameterIndex, boolean x) throws SQLException {
2090                if (this.useTrueBoolean) {
2091                        setInternal(parameterIndex, x ? "'1'" : "'0'"); //$NON-NLS-1$ //$NON-NLS-2$
2092                } else {
2093                        setInternal(parameterIndex, x ? "'t'" : "'f'"); //$NON-NLS-1$ //$NON-NLS-2$
2094                }
2095        }
2096 
2097        /**
2098         * Set a parameter to a Java byte value. The driver converts this to a SQL
2099         * TINYINT value when it sends it to the database.
2100         * 
2101         * @param parameterIndex
2102         *            the first parameter is 1...
2103         * @param x
2104         *            the parameter value
2105         * 
2106         * @exception SQLException
2107         *                if a database access error occurs
2108         */
2109        public void setByte(int parameterIndex, byte x) throws SQLException {
2110                setInternal(parameterIndex, String.valueOf(x));
2111        }
2112 
2113        /**
2114         * Set a parameter to a Java array of bytes. The driver converts this to a
2115         * SQL VARBINARY or LONGVARBINARY (depending on the argument's size relative
2116         * to the driver's limits on VARBINARYs) when it sends it to the database.
2117         * 
2118         * @param parameterIndex
2119         *            the first parameter is 1...
2120         * @param x
2121         *            the parameter value
2122         * 
2123         * @exception SQLException
2124         *                if a database access error occurs
2125         */
2126        public void setBytes(int parameterIndex, byte[] x) throws SQLException {
2127                setBytes(parameterIndex, x, true, true);
2128        }
2129 
2130        protected void setBytes(int parameterIndex, byte[] x,
2131                        boolean checkForIntroducer, boolean escapeForMBChars)
2132                        throws SQLException {
2133                if (x == null) {
2134                        setNull(parameterIndex, java.sql.Types.BINARY);
2135                } else {
2136                        String connectionEncoding = this.connection.getEncoding();
2137 
2138                        if (escapeForMBChars && this.connection.getUseUnicode()
2139                                        && connectionEncoding != null
2140                                        && CharsetMapping.isMultibyteCharset(connectionEncoding)) {
2141 
2142                                // Send as hex
2143 
2144                                ByteArrayOutputStream bOut = new ByteArrayOutputStream(
2145                                                (x.length * 2) + 3);
2146                                bOut.write('x');
2147                                bOut.write('\'');
2148 
2149                                for (int i = 0; i < x.length; i++) {
2150                                        int lowBits = (x[i] & 0xff) / 16;
2151                                        int highBits = (x[i] & 0xff) % 16;
2152 
2153                                        bOut.write(HEX_DIGITS[lowBits]);
2154                                        bOut.write(HEX_DIGITS[highBits]);
2155                                }
2156 
2157                                bOut.write('\'');
2158 
2159                                setInternal(parameterIndex, bOut.toByteArray());
2160 
2161                                return;
2162                        }
2163 
2164                        // escape them
2165                        int numBytes = x.length;
2166 
2167                        int pad = 2;
2168 
2169                        boolean needsIntroducer = checkForIntroducer
2170                                        && this.connection.versionMeetsMinimum(4, 1, 0);
2171 
2172                        if (needsIntroducer) {
2173                                pad += 7;
2174                        }
2175 
2176                        ByteArrayOutputStream bOut = new ByteArrayOutputStream(numBytes
2177                                        + pad);
2178 
2179                        if (needsIntroducer) {
2180                                bOut.write('_');
2181                                bOut.write('b');
2182                                bOut.write('i');
2183                                bOut.write('n');
2184                                bOut.write('a');
2185                                bOut.write('r');
2186                                bOut.write('y');
2187                        }
2188                        bOut.write('\'');
2189 
2190                        for (int i = 0; i < numBytes; ++i) {
2191                                byte b = x[i];
2192 
2193                                switch (b) {
2194                                case 0: /* Must be escaped for 'mysql' */
2195                                        bOut.write('\\');
2196                                        bOut.write('0');
2197 
2198                                        break;
2199 
2200                                case '\n': /* Must be escaped for logs */
2201                                        bOut.write('\\');
2202                                        bOut.write('n');
2203 
2204                                        break;
2205 
2206                                case '\r':
2207                                        bOut.write('\\');
2208                                        bOut.write('r');
2209 
2210                                        break;
2211 
2212                                case '\\':
2213                                        bOut.write('\\');
2214                                        bOut.write('\\');
2215 
2216                                        break;
2217 
2218                                case '\'':
2219                                        bOut.write('\\');
2220                                        bOut.write('\'');
2221 
2222                                        break;
2223 
2224                                case '"': /* Better safe than sorry */
2225                                        bOut.write('\\');
2226                                        bOut.write('"');
2227 
2228                                        break;
2229 
2230                                case '\032': /* This gives problems on Win32 */
2231                                        bOut.write('\\');
2232                                        bOut.write('Z');
2233 
2234                                        break;
2235 
2236                                default:
2237                                        bOut.write(b);
2238                                }
2239                        }
2240 
2241                        bOut.write('\'');
2242 
2243                        setInternal(parameterIndex, bOut.toByteArray());
2244                }
2245        }
2246 
2247        /**
2248         * Used by updatable result sets for refreshRow() because the parameter has
2249         * already been escaped for updater or inserter prepared statements.
2250         * 
2251         * @param parameterIndex
2252         *            the parameter to set.
2253         * @param parameterAsBytes
2254         *            the parameter as a string.
2255         * 
2256         * @throws SQLException
2257         *             if an error occurs
2258         */
2259        protected void setBytesNoEscape(int parameterIndex, byte[] parameterAsBytes)
2260                        throws SQLException {
2261                byte[] parameterWithQuotes = new byte[parameterAsBytes.length + 2];
2262                parameterWithQuotes[0] = '\'';
2263                System.arraycopy(parameterAsBytes, 0, parameterWithQuotes, 1,
2264                                parameterAsBytes.length);
2265                parameterWithQuotes[parameterAsBytes.length + 1] = '\'';
2266 
2267                setInternal(parameterIndex, parameterWithQuotes);
2268        }
2269 
2270        protected void setBytesNoEscapeNoQuotes(int parameterIndex,
2271                        byte[] parameterAsBytes) throws SQLException {
2272                setInternal(parameterIndex, parameterAsBytes);
2273        }
2274 
2275        /**
2276         * JDBC 2.0 When a very large UNICODE value is input to a LONGVARCHAR
2277         * parameter, it may be more practical to send it via a java.io.Reader. JDBC
2278         * will read the data from the stream as needed, until it reaches
2279         * end-of-file. The JDBC driver will do any necessary conversion from
2280         * UNICODE to the database char format.
2281         * 
2282         * <P>
2283         * <B>Note:</B> This stream object can either be a standard Java stream
2284         * object or your own subclass that implements the standard interface.
2285         * </p>
2286         * 
2287         * @param parameterIndex
2288         *            the first parameter is 1, the second is 2, ...
2289         * @param reader
2290         *            the java reader which contains the UNICODE data
2291         * @param length
2292         *            the number of characters in the stream
2293         * 
2294         * @exception SQLException
2295         *                if a database-access error occurs.
2296         */
2297        public void setCharacterStream(int parameterIndex, java.io.Reader reader,
2298                        int length) throws SQLException {
2299                try {
2300                        if (reader == null) {
2301                                setNull(parameterIndex, Types.LONGVARCHAR);
2302                        } else {
2303                                char[] c = null;
2304                                int len = 0;
2305 
2306                                boolean useLength = this.connection
2307                                                .getUseStreamLengthsInPrepStmts();
2308 
2309                                if (useLength && (length != -1)) {
2310                                        c = new char[length];
2311 
2312                                        int numCharsRead = readFully(reader, c, length); // blocks
2313                                        // until
2314                                        // all
2315                                        // read
2316 
2317                                        setString(parameterIndex, new String(c, 0, numCharsRead));
2318                                } else {
2319                                        c = new char[4096];
2320 
2321                                        StringBuffer buf = new StringBuffer();
2322 
2323                                        while ((len = reader.read(c)) != -1) {
2324                                                buf.append(c, 0, len);
2325                                        }
2326 
2327                                        setString(parameterIndex, buf.toString());
2328                                }
2329                        }
2330                } catch (java.io.IOException ioEx) {
2331                        throw new SQLException(ioEx.toString(),
2332                                        SQLError.SQL_STATE_GENERAL_ERROR);
2333                }
2334        }
2335 
2336        /**
2337         * JDBC 2.0 Set a CLOB parameter.
2338         * 
2339         * @param i
2340         *            the first parameter is 1, the second is 2, ...
2341         * @param x
2342         *            an object representing a CLOB
2343         * 
2344         * @throws SQLException
2345         *             if a database error occurs
2346         */
2347        public void setClob(int i, Clob x) throws SQLException {
2348                if (x == null) {
2349                        setNull(i, Types.CLOB);
2350 
2351                        return;
2352                }
2353 
2354                setString(i, x.getSubString(1L, (int) x.length()));
2355        }
2356 
2357        /**
2358         * Set a parameter to a java.sql.Date value. The driver converts this to a
2359         * SQL DATE value when it sends it to the database.
2360         * 
2361         * @param parameterIndex
2362         *            the first parameter is 1...
2363         * @param x
2364         *            the parameter value
2365         * 
2366         * @exception java.sql.SQLException
2367         *                if a database access error occurs
2368         */
2369        public void setDate(int parameterIndex, java.sql.Date x)
2370                        throws java.sql.SQLException {
2371                if (x == null) {
2372                        setNull(parameterIndex, java.sql.Types.DATE);
2373                } else {
2374                        // FIXME: Have instance version of this, problem as it's
2375                        // not thread-safe :(
2376                        SimpleDateFormat dateFormatter = new SimpleDateFormat(
2377                                        "''yyyy-MM-dd''", Locale.US); //$NON-NLS-1$
2378                        setInternal(parameterIndex, dateFormatter.format(x));
2379                }
2380        }
2381 
2382        /**
2383         * Set a parameter to a java.sql.Date value. The driver converts this to a
2384         * SQL DATE value when it sends it to the database.
2385         * 
2386         * @param parameterIndex
2387         *            the first parameter is 1, the second is 2, ...
2388         * @param x
2389         *            the parameter value
2390         * @param cal
2391         *            the calendar to interpret the date with
2392         * 
2393         * @exception SQLException
2394         *                if a database-access error occurs.
2395         */
2396        public void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
2397                        throws SQLException {
2398                setDate(parameterIndex, x);
2399        }
2400 
2401        /**
2402         * Set a parameter to a Java double value. The driver converts this to a SQL
2403         * DOUBLE value when it sends it to the database
2404         * 
2405         * @param parameterIndex
2406         *            the first parameter is 1...
2407         * @param x
2408         *            the parameter value
2409         * 
2410         * @exception SQLException
2411         *                if a database access error occurs
2412         */
2413        public void setDouble(int parameterIndex, double x) throws SQLException {
2414 
2415                if (!this.connection.getAllowNanAndInf()
2416                                && (x == Double.POSITIVE_INFINITY
2417                                                || x == Double.NEGATIVE_INFINITY || Double.isNaN(x))) {
2418                        throw new SQLException("'" + x
2419                                        + "' is not a valid numeric or approximate numeric value",
2420                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2421 
2422                }
2423 
2424                setInternal(parameterIndex, StringUtils.fixDecimalExponent(String
2425                                .valueOf(x)));
2426        }
2427 
2428        /**
2429         * Set a parameter to a Java float value. The driver converts this to a SQL
2430         * FLOAT value when it sends it to the database.
2431         * 
2432         * @param parameterIndex
2433         *            the first parameter is 1...
2434         * @param x
2435         *            the parameter value
2436         * 
2437         * @exception SQLException
2438         *                if a database access error occurs
2439         */
2440        public void setFloat(int parameterIndex, float x) throws SQLException {
2441                setInternal(parameterIndex, StringUtils.fixDecimalExponent(String
2442                                .valueOf(x)));
2443        }
2444 
2445        /**
2446         * Set a parameter to a Java int value. The driver converts this to a SQL
2447         * INTEGER value when it sends it to the database.
2448         * 
2449         * @param parameterIndex
2450         *            the first parameter is 1...
2451         * @param x
2452         *            the parameter value
2453         * 
2454         * @exception SQLException
2455         *                if a database access error occurs
2456         */
2457        public void setInt(int parameterIndex, int x) throws SQLException {
2458                setInternal(parameterIndex, String.valueOf(x));
2459        }
2460 
2461        private final void setInternal(int paramIndex, byte[] val)
2462                        throws SQLException {
2463                if (this.isClosed) {
2464                        throw new SQLException(Messages.getString("PreparedStatement.48"), //$NON-NLS-1$
2465                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2466                }
2467 
2468                if ((paramIndex < 1)) {
2469                        throw new SQLException(
2470                                        Messages.getString("PreparedStatement.49") //$NON-NLS-1$
2471                                                        + paramIndex
2472                                                        + Messages.getString("PreparedStatement.50"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
2473                } else if (paramIndex > this.parameterCount) {
2474                        throw new SQLException(
2475                                        Messages.getString("PreparedStatement.51") //$NON-NLS-1$
2476                                                        + paramIndex
2477                                                        + Messages.getString("PreparedStatement.52") + (this.parameterValues.length) + Messages.getString("PreparedStatement.53"), //$NON-NLS-1$ //$NON-NLS-2$
2478                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2479                }
2480 
2481                this.isStream[paramIndex - 1] = false;
2482                this.isNull[paramIndex - 1] = false;
2483                this.parameterStreams[paramIndex - 1] = null;
2484                this.parameterValues[paramIndex - 1] = val;
2485        }
2486 
2487        private final void setInternal(int paramIndex, String val)
2488                        throws SQLException {
2489                byte[] parameterAsBytes = null;
2490 
2491                if (this.charConverter != null) {
2492                        parameterAsBytes = this.charConverter.toBytes(val);
2493                } else {
2494                        parameterAsBytes = StringUtils.getBytes(val, this.charConverter,
2495                                        this.charEncoding, this.connection
2496                                                        .getServerCharacterEncoding(), this.connection
2497                                                        .parserKnowsUnicode());
2498                }
2499 
2500                setInternal(paramIndex, parameterAsBytes);
2501        }
2502 
2503        /**
2504         * Set a parameter to a Java long value. The driver converts this to a SQL
2505         * BIGINT value when it sends it to the database.
2506         * 
2507         * @param parameterIndex
2508         *            the first parameter is 1...
2509         * @param x
2510         *            the parameter value
2511         * 
2512         * @exception SQLException
2513         *                if a database access error occurs
2514         */
2515        public void setLong(int parameterIndex, long x) throws SQLException {
2516                setInternal(parameterIndex, String.valueOf(x));
2517        }
2518 
2519        /**
2520         * Set a parameter to SQL NULL
2521         * 
2522         * <p>
2523         * <B>Note:</B> You must specify the parameters SQL type (although MySQL
2524         * ignores it)
2525         * </p>
2526         * 
2527         * @param parameterIndex
2528         *            the first parameter is 1, etc...
2529         * @param sqlType
2530         *            the SQL type code defined in java.sql.Types
2531         * 
2532         * @exception SQLException
2533         *                if a database access error occurs
2534         */
2535        public void setNull(int parameterIndex, int sqlType) throws SQLException {
2536                setInternal(parameterIndex, "null"); //$NON-NLS-1$
2537                this.isNull[parameterIndex - 1] = true;
2538        }
2539 
2540        /**
2541         * Set a parameter to SQL NULL.
2542         * 
2543         * <P>
2544         * <B>Note:</B> You must specify the parameter's SQL type.
2545         * </p>
2546         * 
2547         * @param parameterIndex
2548         *            the first parameter is 1, the second is 2, ...
2549         * @param sqlType
2550         *            SQL type code defined by java.sql.Types
2551         * @param arg
2552         *            argument parameters for null
2553         * 
2554         * @exception SQLException
2555         *                if a database-access error occurs.
2556         */
2557        public void setNull(int parameterIndex, int sqlType, String arg)
2558                        throws SQLException {
2559                setNull(parameterIndex, sqlType);
2560        }
2561 
2562        private void setNumericObject(int parameterIndex, Object parameterObj,
2563                        int targetSqlType, int scale) throws SQLException {
2564                Number parameterAsNum;
2565 
2566                if (parameterObj instanceof Boolean) {
2567                        parameterAsNum = ((Boolean) parameterObj).booleanValue() ? new Integer(
2568                                        1)
2569                                        : new Integer(0);
2570                } else if (parameterObj instanceof String) {
2571                        switch (targetSqlType) {
2572                        case Types.BIT:
2573                                boolean parameterAsBoolean = "true"
2574                                                .equalsIgnoreCase((String) parameterObj);
2575 
2576                                parameterAsNum = parameterAsBoolean ? new Integer(1)
2577                                                : new Integer(0);
2578 
2579                                break;
2580 
2581                        case Types.TINYINT:
2582                        case Types.SMALLINT:
2583                        case Types.INTEGER:
2584                                parameterAsNum = Integer.valueOf((String) parameterObj);
2585 
2586                                break;
2587 
2588                        case Types.BIGINT:
2589                                parameterAsNum = Long.valueOf((String) parameterObj);
2590 
2591                                break;
2592 
2593                        case Types.REAL:
2594                                parameterAsNum = Float.valueOf((String) parameterObj);
2595 
2596                                break;
2597 
2598                        case Types.FLOAT:
2599                        case Types.DOUBLE:
2600                                parameterAsNum = Double.valueOf((String) parameterObj);
2601 
2602                                break;
2603 
2604                        case Types.DECIMAL:
2605                        case Types.NUMERIC:
2606                        default:
2607                                parameterAsNum = new java.math.BigDecimal((String) parameterObj);
2608                        }
2609                } else {
2610                        parameterAsNum = (Number) parameterObj;
2611                }
2612 
2613                switch (targetSqlType) {
2614                case Types.BIT:
2615                case Types.TINYINT:
2616                case Types.SMALLINT:
2617                case Types.INTEGER:
2618                        setInt(parameterIndex, parameterAsNum.intValue());
2619 
2620                        break;
2621 
2622                case Types.BIGINT:
2623                        setLong(parameterIndex, parameterAsNum.longValue());
2624 
2625                        break;
2626 
2627                case Types.REAL:
2628                        setFloat(parameterIndex, parameterAsNum.floatValue());
2629 
2630                        break;
2631 
2632                case Types.FLOAT:
2633                case Types.DOUBLE:
2634                        setDouble(parameterIndex, parameterAsNum.doubleValue());
2635 
2636                        break;
2637 
2638                case Types.DECIMAL:
2639                case Types.NUMERIC:
2640 
2641                        if (parameterAsNum instanceof java.math.BigDecimal) {
2642                                BigDecimal scaledBigDecimal = null;
2643 
2644                                try {
2645                                        scaledBigDecimal = ((java.math.BigDecimal) parameterAsNum)
2646                                                        .setScale(scale);
2647                                } catch (ArithmeticException ex) {
2648                                        try {
2649                                                scaledBigDecimal = ((java.math.BigDecimal) parameterAsNum)
2650                                                                .setScale(scale, BigDecimal.ROUND_HALF_UP);
2651                                        } catch (ArithmeticException arEx) {
2652                                                throw new SQLException("Can't set scale of '" + scale
2653                                                                + "' for DECIMAL argument '" + parameterAsNum
2654                                                                + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2655                                        }
2656                                }
2657 
2658                                setBigDecimal(parameterIndex, scaledBigDecimal);
2659                        } else if (parameterAsNum instanceof java.math.BigInteger) {
2660                                setBigDecimal(parameterIndex, new java.math.BigDecimal(
2661                                                (java.math.BigInteger) parameterAsNum, scale));
2662                        } else {
2663                                setBigDecimal(parameterIndex, new java.math.BigDecimal(
2664                                                parameterAsNum.doubleValue()));
2665                        }
2666 
2667                        break;
2668                }
2669        }
2670 
2671        /**
2672         * DOCUMENT ME!
2673         * 
2674         * @param parameterIndex
2675         *            DOCUMENT ME!
2676         * @param parameterObj
2677         *            DOCUMENT ME!
2678         * 
2679         * @throws SQLException
2680         *             DOCUMENT ME!
2681         */
2682        public void setObject(int parameterIndex, Object parameterObj)
2683                        throws SQLException {
2684                if (parameterObj == null) {
2685                        setNull(parameterIndex, java.sql.Types.OTHER);
2686                } else {
2687                        if (parameterObj instanceof Byte) {
2688                                setInt(parameterIndex, ((Byte) parameterObj).intValue());
2689                        } else if (parameterObj instanceof String) {
2690                                setString(parameterIndex, (String) parameterObj);
2691                        } else if (parameterObj instanceof BigDecimal) {
2692                                setBigDecimal(parameterIndex, (BigDecimal) parameterObj);
2693                        } else if (parameterObj instanceof Short) {
2694                                setShort(parameterIndex, ((Short) parameterObj).shortValue());
2695                        } else if (parameterObj instanceof Integer) {
2696                                setInt(parameterIndex, ((Integer) parameterObj).intValue());
2697                        } else if (parameterObj instanceof Long) {
2698                                setLong(parameterIndex, ((Long) parameterObj).longValue());
2699                        } else if (parameterObj instanceof Float) {
2700                                setFloat(parameterIndex, ((Float) parameterObj).floatValue());
2701                        } else if (parameterObj instanceof Double) {
2702                                setDouble(parameterIndex, ((Double) parameterObj).doubleValue());
2703                        } else if (parameterObj instanceof byte[]) {
2704                                setBytes(parameterIndex, (byte[]) parameterObj);
2705                        } else if (parameterObj instanceof java.sql.Date) {
2706                                setDate(parameterIndex, (java.sql.Date) parameterObj);
2707                        } else if (parameterObj instanceof Time) {
2708                                setTime(parameterIndex, (Time) parameterObj);
2709                        } else if (parameterObj instanceof Timestamp) {
2710                                setTimestamp(parameterIndex, (Timestamp) parameterObj);
2711                        } else if (parameterObj instanceof Boolean) {
2712                                setBoolean(parameterIndex, ((Boolean) parameterObj)
2713                                                .booleanValue());
2714                        } else if (parameterObj instanceof InputStream) {
2715                                setBinaryStream(parameterIndex, (InputStream) parameterObj, -1);
2716                        } else if (parameterObj instanceof java.sql.Blob) {
2717                                setBlob(parameterIndex, (java.sql.Blob) parameterObj);
2718                        } else if (parameterObj instanceof java.sql.Clob) {
2719                                setClob(parameterIndex, (java.sql.Clob) parameterObj);
2720                        } else if (parameterObj instanceof java.util.Date) {
2721                                setTimestamp(parameterIndex, new Timestamp(
2722                                                ((java.util.Date) parameterObj).getTime()));
2723                        } else if (parameterObj instanceof BigInteger) {
2724                                setString(parameterIndex, parameterObj.toString());
2725                        } else {
2726                                setSerializableObject(parameterIndex, parameterObj);
2727                        }
2728                }
2729        }
2730 
2731        /**
2732         * DOCUMENT ME!
2733         * 
2734         * @param parameterIndex
2735         *            DOCUMENT ME!
2736         * @param parameterObj
2737         *            DOCUMENT ME!
2738         * @param targetSqlType
2739         *            DOCUMENT ME!
2740         * 
2741         * @throws SQLException
2742         *             DOCUMENT ME!
2743         */
2744        public void setObject(int parameterIndex, Object parameterObj,
2745                        int targetSqlType) throws SQLException {
2746                if (!(parameterObj instanceof BigDecimal)) {
2747                        setObject(parameterIndex, parameterObj, targetSqlType, 0);
2748                } else {
2749                        setObject(parameterIndex, parameterObj, targetSqlType,
2750                                        ((BigDecimal)parameterObj).scale());
2751                }
2752        }
2753 
2754        /**
2755         * Set the value of a parameter using an object; use the java.lang
2756         * equivalent objects for integral values.
2757         * 
2758         * <P>
2759         * The given Java object will be converted to the targetSqlType before being
2760         * sent to the database.
2761         * </p>
2762         * 
2763         * <P>
2764         * note that this method may be used to pass database-specific abstract data
2765         * types. This is done by using a Driver-specific Java type and using a
2766         * targetSqlType of java.sql.Types.OTHER
2767         * </p>
2768         * 
2769         * @param parameterIndex
2770         *            the first parameter is 1...
2771         * @param parameterObj
2772         *            the object containing the input parameter value
2773         * @param targetSqlType
2774         *            The SQL type to be send to the database
2775         * @param scale
2776         *            For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2777         *            this is the number of digits after the decimal. For all other
2778         *            types this value will be ignored.
2779         * 
2780         * @throws SQLException
2781         *             if a database access error occurs
2782         */
2783        public void setObject(int parameterIndex, Object parameterObj,
2784                        int targetSqlType, int scale) throws SQLException {
2785                if (parameterObj == null) {
2786                        setNull(parameterIndex, java.sql.Types.OTHER);
2787                } else {
2788                        try {
2789                                switch (targetSqlType) {
2790                                case Types.BOOLEAN:
2791                                        /*
2792                                         * From Table-B5 in the JDBC-3.0 Spec
2793                                         * 
2794                                         * T S I B R F D D N B B C V L I M N I E L O E U I O H A O N
2795                                         * A T G A O U C M T O A R N Y L E I L A B I E L R C G I L G
2796                                         * N T L M R E H V N I E T E A I A A A T N R L C N R R T C H
2797                                         * A R ----------------------------------- Boolean x x x x x
2798                                         * x x x x x x x x x
2799                                         */
2800 
2801                                        if (parameterObj instanceof Boolean) {
2802                                                setBoolean(parameterIndex, ((Boolean) parameterObj)
2803                                                                .booleanValue());
2804 
2805                                                break;
2806                                        } else if (parameterObj instanceof String) {
2807                                                setBoolean(parameterIndex, "true"
2808                                                                .equalsIgnoreCase((String) parameterObj)
2809                                                                || !"0".equalsIgnoreCase((String) parameterObj));
2810 
2811                                                break;
2812                                        } else if (parameterObj instanceof Number) {
2813                                                int intValue = ((Number) parameterObj).intValue();
2814 
2815                                                setBoolean(parameterIndex, intValue != 0);
2816 
2817                                                break;
2818                                        } else {
2819                                                throw new SQLException("No conversion from "
2820                                                                + parameterObj.getClass().getName()
2821                                                                + " to Types.BOOLEAN possible.",
2822                                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2823                                        }
2824 
2825                                case Types.BIT:
2826                                case Types.TINYINT:
2827                                case Types.SMALLINT:
2828                                case Types.INTEGER:
2829                                case Types.BIGINT:
2830                                case Types.REAL:
2831                                case Types.FLOAT:
2832                                case Types.DOUBLE:
2833                                case Types.DECIMAL:
2834                                case Types.NUMERIC:
2835 
2836                                        setNumericObject(parameterIndex, parameterObj,
2837                                                        targetSqlType, scale);
2838 
2839                                        break;
2840 
2841                                case Types.CHAR:
2842                                case Types.VARCHAR:
2843                                case Types.LONGVARCHAR:
2844                                        if (parameterObj instanceof BigDecimal) {
2845                                                setString(
2846                                                                parameterIndex,
2847                                                                (StringUtils
2848                                                                                .fixDecimalExponent(StringUtils
2849                                                                                                .consistentToString((BigDecimal) parameterObj))));
2850                                        } else {
2851                                                setString(parameterIndex, parameterObj.toString());
2852                                        }
2853 
2854                                        break;
2855 
2856                                case Types.CLOB:
2857 
2858                                        if (parameterObj instanceof java.sql.Clob) {
2859                                                setClob(parameterIndex, (java.sql.Clob) parameterObj);
2860                                        } else {
2861                                                setString(parameterIndex, parameterObj.toString());
2862                                        }
2863 
2864                                        break;
2865 
2866                                case Types.BINARY:
2867                                case Types.VARBINARY:
2868                                case Types.LONGVARBINARY:
2869                                case Types.BLOB:
2870 
2871                                        if (parameterObj instanceof byte[]) {
2872                                                setBytes(parameterIndex, (byte[]) parameterObj);
2873                                        } else if (parameterObj instanceof java.sql.Blob) {
2874                                                setBlob(parameterIndex, (java.sql.Blob) parameterObj);
2875                                        } else {
2876                                                setBytes(parameterIndex, StringUtils.getBytes(
2877                                                                parameterObj.toString(), this.charConverter,
2878                                                                this.charEncoding, this.connection
2879                                                                                .getServerCharacterEncoding(),
2880                                                                this.connection.parserKnowsUnicode()));
2881                                        }
2882 
2883                                        break;
2884 
2885                                case Types.DATE:
2886                                case Types.TIMESTAMP:
2887 
2888                                        java.util.Date parameterAsDate;
2889 
2890                                        if (parameterObj instanceof String) {
2891                                                ParsePosition pp = new ParsePosition(0);
2892                                                java.text.DateFormat sdf = new java.text.SimpleDateFormat(
2893                                                                getDateTimePattern((String) parameterObj, false),
2894                                                                Locale.US);
2895                                                parameterAsDate = sdf.parse((String) parameterObj, pp);
2896                                        } else {
2897                                                parameterAsDate = (java.util.Date) parameterObj;
2898                                        }
2899 
2900                                        switch (targetSqlType) {
2901                                        case Types.DATE:
2902 
2903                                                if (parameterAsDate instanceof java.sql.Date) {
2904                                                        setDate(parameterIndex,
2905                                                                        (java.sql.Date) parameterAsDate);
2906                                                } else {
2907                                                        setDate(parameterIndex, new java.sql.Date(
2908                                                                        parameterAsDate.getTime()));
2909                                                }
2910 
2911                                                break;
2912 
2913                                        case Types.TIMESTAMP:
2914 
2915                                                if (parameterAsDate instanceof java.sql.Timestamp) {
2916                                                        setTimestamp(parameterIndex,
2917                                                                        (java.sql.Timestamp) parameterAsDate);
2918                                                } else {
2919                                                        setTimestamp(parameterIndex,
2920                                                                        new java.sql.Timestamp(parameterAsDate
2921                                                                                        .getTime()));
2922                                                }
2923 
2924                                                break;
2925                                        }
2926 
2927                                        break;
2928 
2929                                case Types.TIME:
2930 
2931                                        if (parameterObj instanceof String) {
2932                                                java.text.DateFormat sdf = new java.text.SimpleDateFormat(
2933                                                                getDateTimePattern((String) parameterObj, true),
2934                                                                Locale.US);
2935                                                setTime(parameterIndex, new java.sql.Time(sdf.parse(
2936                                                                (String) parameterObj).getTime()));
2937                                        } else if (parameterObj instanceof Timestamp) {
2938                                                Timestamp xT = (Timestamp) parameterObj;
2939                                                setTime(parameterIndex, new java.sql.Time(xT.getTime()));
2940                                        } else {
2941                                                setTime(parameterIndex, (java.sql.Time) parameterObj);
2942                                        }
2943 
2944                                        break;
2945 
2946                                case Types.OTHER:
2947                                        setSerializableObject(parameterIndex, parameterObj);
2948 
2949                                        break;
2950 
2951                                default:
2952                                        throw new SQLException(Messages
2953                                                        .getString("PreparedStatement.16"), //$NON-NLS-1$
2954                                                        SQLError.SQL_STATE_GENERAL_ERROR);
2955                                }
2956                        } catch (Exception ex) {
2957                                if (ex instanceof SQLException) {
2958                                        throw (SQLException) ex;
2959                                }
2960 
2961                                throw new SQLException(
2962                                                Messages.getString("PreparedStatement.17") //$NON-NLS-1$
2963                                                                + parameterObj.getClass().toString()
2964                                                                + Messages.getString("PreparedStatement.18") //$NON-NLS-1$
2965                                                                + ex.getClass().getName()
2966                                                                + Messages.getString("PreparedStatement.19") + ex.getMessage(), //$NON-NLS-1$
2967                                                SQLError.SQL_STATE_GENERAL_ERROR);
2968                        }
2969                }
2970        }
2971 
2972        private int setOneBatchedParameterSet(
2973                        java.sql.PreparedStatement batchedStatement, int batchedParamIndex,
2974                        BatchParams paramArg) throws SQLException {
2975                boolean[] isNullBatch = paramArg.isNull;
2976                boolean[] isStreamBatch = paramArg.isStream;
2977 
2978                for (int j = 0; j < isNullBatch.length; j++) {
2979                        if (isNullBatch[j]) {
2980                                batchedStatement.setNull(batchedParamIndex++, Types.NULL);
2981                        } else {
2982                                if (isStreamBatch[j]) {
2983                                        batchedStatement.setBinaryStream(batchedParamIndex++,
2984                                                        paramArg.parameterStreams[j],
2985                                                        paramArg.streamLengths[j]);
2986                                } else {
2987                                        ((com.mysql.jdbc.PreparedStatement) batchedStatement)
2988                                                        .setBytesNoEscapeNoQuotes(batchedParamIndex++,
2989                                                                        paramArg.parameterStrings[j]);
2990                                }
2991                        }
2992                }
2993 
2994                return batchedParamIndex;
2995        }
2996 
2997        /**
2998         * JDBC 2.0 Set a REF(&lt;structured-type&gt;) parameter.
2999         * 
3000         * @param i
3001         *            the first parameter is 1, the second is 2, ...
3002         * @param x
3003         *            an object representing data of an SQL REF Type
3004         * 
3005         * @throws SQLException
3006         *             if a database error occurs
3007         * @throws NotImplemented
3008         *             DOCUMENT ME!
3009         */
3010        public void setRef(int i, Ref x) throws SQLException {
3011                throw new NotImplemented();
3012        }
3013 
3014        /**
3015         * Sets the concurrency for result sets generated by this statement
3016         * 
3017         * @param concurrencyFlag
3018         *            DOCUMENT ME!
3019         */
3020        void setResultSetConcurrency(int concurrencyFlag) {
3021                this.resultSetConcurrency = concurrencyFlag;
3022        }
3023 
3024        /**
3025         * Sets the result set type for result sets generated by this statement
3026         * 
3027         * @param typeFlag
3028         *            DOCUMENT ME!
3029         */
3030        void setResultSetType(int typeFlag) {
3031                this.resultSetType = typeFlag;
3032        }
3033 
3034        /**
3035         * DOCUMENT ME!
3036         * 
3037         * @param retrieveGeneratedKeys
3038         */
3039        protected void setRetrieveGeneratedKeys(boolean retrieveGeneratedKeys) {
3040                this.retrieveGeneratedKeys = retrieveGeneratedKeys;
3041        }
3042 
3043        /**
3044         * Sets the value for the placeholder as a serialized Java object (used by
3045         * various forms of setObject()
3046         * 
3047         * @param parameterIndex
3048         *            DOCUMENT ME!
3049         * @param parameterObj
3050         *            DOCUMENT ME!
3051         * 
3052         * @throws SQLException
3053         *             DOCUMENT ME!
3054         */
3055        private final void setSerializableObject(int parameterIndex,
3056                        Object parameterObj) throws SQLException {
3057                try {
3058                        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
3059                        ObjectOutputStream objectOut = new ObjectOutputStream(bytesOut);
3060                        objectOut.writeObject(parameterObj);
3061                        objectOut.flush();
3062                        objectOut.close();
3063                        bytesOut.flush();
3064                        bytesOut.close();
3065 
3066                        byte[] buf = bytesOut.toByteArray();
3067                        ByteArrayInputStream bytesIn = new ByteArrayInputStream(buf);
3068                        setBinaryStream(parameterIndex, bytesIn, buf.length);
3069                } catch (Exception ex) {
3070                        throw new SQLException(Messages.getString("PreparedStatement.54") //$NON-NLS-1$
3071                                        + ex.getClass().getName(),
3072                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3073                }
3074        }
3075 
3076        /**
3077         * Set a parameter to a Java short value. The driver converts this to a SQL
3078         * SMALLINT value when it sends it to the database.
3079         * 
3080         * @param parameterIndex
3081         *            the first parameter is 1...
3082         * @param x
3083         *            the parameter value
3084         * 
3085         * @exception SQLException
3086         *                if a database access error occurs
3087         */
3088        public void setShort(int parameterIndex, short x) throws SQLException {
3089                setInternal(parameterIndex, String.valueOf(x));
3090        }
3091 
3092        /**
3093         * Set a parameter to a Java String value. The driver converts this to a SQL
3094         * VARCHAR or LONGVARCHAR value (depending on the arguments size relative to
3095         * the driver's limits on VARCHARs) when it sends it to the database.
3096         * 
3097         * @param parameterIndex
3098         *            the first parameter is 1...
3099         * @param x
3100         *            the parameter value
3101         * 
3102         * @exception SQLException
3103         *                if a database access error occurs
3104         */
3105        public void setString(int parameterIndex, String x) throws SQLException {
3106                // if the passed string is null, then set this column to null
3107                if (x == null) {
3108                        setNull(parameterIndex, Types.CHAR);
3109                } else {
3110                        StringBuffer buf = new StringBuffer((int) (x.length() * 1.1));
3111                        buf.append('\'');
3112 
3113                        int stringLength = x.length();
3114 
3115                        //
3116                        // Note: buf.append(char) is _faster_ than
3117                        // appending in blocks, because the block
3118                        // append requires a System.arraycopy()....
3119                        // go figure...
3120                        //
3121                        for (int i = 0; i < stringLength; ++i) {
3122                                char c = x.charAt(i);
3123 
3124                                switch (c) {
3125                                case 0: /* Must be escaped for 'mysql' */
3126                                        buf.append('\\');
3127                                        buf.append('0');
3128 
3129                                        break;
3130 
3131                                case '\n': /* Must be escaped for logs */
3132                                        buf.append('\\');
3133                                        buf.append('n');
3134 
3135                                        break;
3136 
3137                                case '\r':
3138                                        buf.append('\\');
3139                                        buf.append('r');
3140 
3141                                        break;
3142 
3143                                case '\\':
3144                                        buf.append('\\');
3145                                        buf.append('\\');
3146 
3147                                        break;
3148 
3149                                case '\'':
3150                                        buf.append('\\');
3151                                        buf.append('\'');
3152 
3153                                        break;
3154 
3155                                case '"': /* Better safe than sorry */
3156                                        if (this.usingAnsiMode) {
3157                                                buf.append('\\');
3158                                        }
3159 
3160                                        buf.append('"');
3161 
3162                                        break;
3163 
3164                                case '\032': /* This gives problems on Win32 */
3165                                        buf.append('\\');
3166                                        buf.append('Z');
3167 
3168                                        break;
3169 
3170                                default:
3171                                        buf.append(c);
3172                                }
3173                        }
3174 
3175                        buf.append('\'');
3176 
3177                        String parameterAsString = buf.toString();
3178 
3179                        byte[] parameterAsBytes = null;
3180 
3181                        if (!this.isLoadDataQuery) {
3182                                parameterAsBytes = StringUtils.getBytes(parameterAsString,
3183                                                this.charConverter, this.charEncoding, this.connection
3184                                                                .getServerCharacterEncoding(), this.connection
3185                                                                .parserKnowsUnicode());
3186                        } else {
3187                                // Send with platform character encoding
3188                                parameterAsBytes = parameterAsString.getBytes();
3189                        }
3190 
3191                        setInternal(parameterIndex, parameterAsBytes);
3192                }
3193        }
3194 
3195        /**
3196         * Set a parameter to a java.sql.Time value. The driver converts this to a
3197         * SQL TIME value when it sends it to the database.
3198         * 
3199         * @param parameterIndex
3200         *            the first parameter is 1, the second is 2, ...
3201         * @param x
3202         *            the parameter value
3203         * @param cal
3204         *            the cal specifying the timezone
3205         * 
3206         * @throws SQLException
3207         *             if a database-access error occurs.
3208         */
3209        public void setTime(int parameterIndex, java.sql.Time x, Calendar cal)
3210                        throws SQLException {
3211                setTimeInternal(parameterIndex, x, cal.getTimeZone(), true);
3212        }
3213 
3214        /**
3215         * Set a parameter to a java.sql.Time value. The driver converts this to a
3216         * SQL TIME value when it sends it to the database.
3217         * 
3218         * @param parameterIndex
3219         *            the first parameter is 1...));
3220         * @param x
3221         *            the parameter value
3222         * 
3223         * @throws java.sql.SQLException
3224         *             if a database access error occurs
3225         */
3226        public void setTime(int parameterIndex, Time x)
3227                        throws java.sql.SQLException {
3228                setTimeInternal(parameterIndex, x, TimeZone.getDefault(), false);
3229        }
3230 
3231        /**
3232         * Set a parameter to a java.sql.Time value. The driver converts this to a
3233         * SQL TIME value when it sends it to the database, using the given
3234         * timezone.
3235         * 
3236         * @param parameterIndex
3237         *            the first parameter is 1...));
3238         * @param x
3239         *            the parameter value
3240         * @param tz
3241         *            the timezone to use
3242         * 
3243         * @throws java.sql.SQLException
3244         *             if a database access error occurs
3245         */
3246        private void setTimeInternal(int parameterIndex, Time x, TimeZone tz,
3247                        boolean rollForward) throws java.sql.SQLException {
3248                if (x == null) {
3249                        setNull(parameterIndex, java.sql.Types.TIME);
3250                } else {
3251                        x = TimeUtil.changeTimezone(this.connection, x, tz, this.connection
3252                                        .getServerTimezoneTZ(), rollForward);
3253 
3254                        setInternal(parameterIndex, "'" + x.toString() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
3255                }
3256        }
3257 
3258        /**
3259         * Set a parameter to a java.sql.Timestamp value. The driver converts this
3260         * to a SQL TIMESTAMP value when it sends it to the database.
3261         * 
3262         * @param parameterIndex
3263         *            the first parameter is 1, the second is 2, ...
3264         * @param x
3265         *            the parameter value
3266         * @param cal
3267         *            the calendar specifying the timezone to use
3268         * 
3269         * @throws SQLException
3270         *             if a database-access error occurs.
3271         */
3272        public void setTimestamp(int parameterIndex, java.sql.Timestamp x,
3273                        Calendar cal) throws SQLException {
3274                setTimestampInternal(parameterIndex, x, cal.getTimeZone(), true);
3275        }
3276 
3277        /**
3278         * Set a parameter to a java.sql.Timestamp value. The driver converts this
3279         * to a SQL TIMESTAMP value when it sends it to the database.
3280         * 
3281         * @param parameterIndex
3282         *            the first parameter is 1...
3283         * @param x
3284         *            the parameter value
3285         * 
3286         * @throws java.sql.SQLException
3287         *             if a database access error occurs
3288         */
3289        public void setTimestamp(int parameterIndex, Timestamp x)
3290                        throws java.sql.SQLException {
3291                setTimestampInternal(parameterIndex, x, TimeZone.getDefault(), false);
3292        }
3293 
3294        /**
3295         * Set a parameter to a java.sql.Timestamp value. The driver converts this
3296         * to a SQL TIMESTAMP value when it sends it to the database.
3297         * 
3298         * @param parameterIndex
3299         *            the first parameter is 1, the second is 2, ...
3300         * @param x
3301         *            the parameter value
3302         * @param tz
3303         *            the timezone to use
3304         * 
3305         * @throws SQLException
3306         *             if a database-access error occurs.
3307         */
3308        private synchronized void setTimestampInternal(int parameterIndex,
3309                        Timestamp x, TimeZone tz, boolean rollForward) throws SQLException {
3310                if (x == null) {
3311                        setNull(parameterIndex, java.sql.Types.TIMESTAMP);
3312                } else {
3313                        String timestampString = null;
3314                        x = TimeUtil.changeTimezone(this.connection, x, tz, this.connection
3315                                        .getServerTimezoneTZ(), rollForward);
3316 
3317                        if (this.tsdf == null) {
3318                                this.tsdf = new SimpleDateFormat(
3319                                                "''yyyy-MM-dd HH:mm:ss''", Locale.US); //$NON-NLS-1$
3320                        }
3321 
3322                        timestampString = this.tsdf.format(x);
3323 
3324                        setInternal(parameterIndex, timestampString); // SimpleDateFormat
3325                        // is not
3326                        // thread-safe
3327                }
3328        }
3329 
3330        /**
3331         * When a very large Unicode value is input to a LONGVARCHAR parameter, it
3332         * may be more practical to send it via a java.io.InputStream. JDBC will
3333         * read the data from the stream as needed, until it reaches end-of-file.
3334         * The JDBC driver will do any necessary conversion from UNICODE to the
3335         * database char format.
3336         * 
3337         * <P>
3338         * <B>Note:</B> This stream object can either be a standard Java stream
3339         * object or your own subclass that implements the standard interface.
3340         * </p>
3341         * 
3342         * @param parameterIndex
3343         *            the first parameter is 1...
3344         * @param x
3345         *            the parameter value
3346         * @param length
3347         *            the number of bytes to read from the stream
3348         * 
3349         * @throws SQLException
3350         *             if a database access error occurs
3351         * 
3352         * @deprecated
3353         */
3354        public void setUnicodeStream(int parameterIndex, InputStream x, int length)
3355                        throws SQLException {
3356                if (x == null) {
3357                        setNull(parameterIndex, java.sql.Types.VARCHAR);
3358                } else {
3359                        setBinaryStream(parameterIndex, x, length);
3360                }
3361        }
3362 
3363        /**
3364         * @see PreparedStatement#setURL(int, URL)
3365         */
3366        public void setURL(int parameterIndex, URL arg) throws SQLException {
3367                if (arg != null) {
3368                        setString(parameterIndex, arg.toString());
3369                } else {
3370                        setNull(parameterIndex, Types.CHAR);
3371                }
3372        }
3373 
3374        private final void streamToBytes(Buffer packet, InputStream in,
3375                        boolean escape, int streamLength, boolean useLength)
3376                        throws SQLException {
3377                try {
3378                        String connectionEncoding = this.connection.getEncoding();
3379 
3380                        boolean hexEscape = false;
3381 
3382                        if (this.connection.getUseUnicode() && connectionEncoding != null
3383                                        && CharsetMapping.isMultibyteCharset(connectionEncoding)
3384                                        && !this.connection.parserKnowsUnicode()) {
3385                                hexEscape = true;
3386                        }
3387 
3388                        if (streamLength == -1) {
3389                                useLength = false;
3390                        }
3391 
3392                        int bc = -1;
3393 
3394                        if (useLength) {
3395                                bc = readblock(in, streamConvertBuf, streamLength);
3396                        } else {
3397                                bc = readblock(in, streamConvertBuf);
3398                        }
3399 
3400                        int lengthLeftToRead = streamLength - bc;
3401 
3402                        if (hexEscape) {
3403                                packet.writeStringNoNull("x");
3404                        } else if (this.connection.getIO().versionMeetsMinimum(4, 1, 0)) {
3405                                packet.writeStringNoNull("_binary");
3406                        }
3407 
3408                        if (escape) {
3409                                packet.writeByte((byte) '\'');
3410                        }
3411 
3412                        while (bc > 0) {
3413                                if (hexEscape) {
3414                                        hexEscapeBlock(streamConvertBuf, packet, bc);
3415                                } else if (escape) {
3416                                        escapeblockFast(streamConvertBuf, packet, bc);
3417                                } else {
3418                                        packet.writeBytesNoNull(streamConvertBuf, 0, bc);
3419                                }
3420 
3421                                if (useLength) {
3422                                        bc = readblock(in, streamConvertBuf, lengthLeftToRead);
3423 
3424                                        if (bc > 0) {
3425                                                lengthLeftToRead -= bc;
3426                                        }
3427                                } else {
3428                                        bc = readblock(in, streamConvertBuf);
3429                                }
3430                        }
3431 
3432                        if (escape) {
3433                                packet.writeByte((byte) '\'');
3434                        }
3435                } finally {
3436                        if (this.connection.getAutoClosePStmtStreams()) {
3437                                try {
3438                                        in.close();
3439                                } catch (IOException ioEx) {
3440                                        ;
3441                                }
3442 
3443                                in = null;
3444                        }
3445                }
3446        }
3447 
3448        private final byte[] streamToBytes(InputStream in, boolean escape,
3449                        int streamLength, boolean useLength) throws SQLException {
3450                try {
3451                        if (streamLength == -1) {
3452                                useLength = false;
3453                        }
3454 
3455                        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
3456 
3457                        int bc = -1;
3458 
3459                        if (useLength) {
3460                                bc = readblock(in, this.streamConvertBuf, streamLength);
3461                        } else {
3462                                bc = readblock(in, this.streamConvertBuf);
3463                        }
3464 
3465                        int lengthLeftToRead = streamLength - bc;
3466 
3467                        if (this.connection.versionMeetsMinimum(4, 1, 0)) {
3468                                bytesOut.write('_');
3469                                bytesOut.write('b');
3470                                bytesOut.write('i');
3471                                bytesOut.write('n');
3472                                bytesOut.write('a');
3473                                bytesOut.write('r');
3474                                bytesOut.write('y');
3475                        }
3476 
3477                        if (escape) {
3478                                bytesOut.write('\'');
3479                        }
3480 
3481                        while (bc > 0) {
3482                                if (escape) {
3483                                        escapeblockFast(this.streamConvertBuf, bytesOut, bc);
3484                                } else {
3485                                        bytesOut.write(this.streamConvertBuf, 0, bc);
3486                                }
3487 
3488                                if (useLength) {
3489                                        bc = readblock(in, this.streamConvertBuf, lengthLeftToRead);
3490 
3491                                        if (bc > 0) {
3492                                                lengthLeftToRead -= bc;
3493                                        }
3494                                } else {
3495                                        bc = readblock(in, this.streamConvertBuf);
3496                                }
3497                        }
3498 
3499                        if (escape) {
3500                                bytesOut.write('\'');
3501                        }
3502 
3503                        return bytesOut.toByteArray();
3504                } finally {
3505                        if (this.connection.getAutoClosePStmtStreams()) {
3506                                try {
3507                                        in.close();
3508                                } catch (IOException ioEx) {
3509                                        ;
3510                                }
3511 
3512                                in = null;
3513                        }
3514                }
3515        }
3516 
3517        /**
3518         * Returns this PreparedStatement represented as a string.
3519         * 
3520         * @return this PreparedStatement represented as a string.
3521         */
3522        public String toString() {
3523                StringBuffer buf = new StringBuffer();
3524                buf.append(super.toString());
3525                buf.append(": "); //$NON-NLS-1$
3526 
3527                try {
3528                        buf.append(asSql());
3529                } catch (SQLException sqlEx) {
3530                        buf.append("EXCEPTION: " + sqlEx.toString());
3531                }
3532 
3533                return buf.toString();
3534        }
3535}

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