EMMA Coverage Report (generated Tue Jul 25 08:38:09 UTC 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [PreparedStatement.java]

nameclass, %method, %block, %line, %
PreparedStatement.java75%  (3/4)87%  (77/89)76%  (4604/6064)78%  (986.4/1267)

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

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