KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2    Copyright (C) 2002 MySQL AB
3
4       This program is free software; you can redistribute it and/or modify
5       it under the terms of the GNU General Public License as published by
6       the Free Software Foundation; either version 2 of the License, or
7       (at your option) any later version.
8
9       This program is distributed in the hope that it will be useful,
10       but WITHOUT ANY WARRANTY; without even the implied warranty of
11       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12       GNU General Public License for more details.
13
14       You should have received a copy of the GNU General Public License
15       along with this program; if not, write to the Free Software
16       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18  */

19 package com.mysql.jdbc;
20
21 import java.io.BufferedInputStream JavaDoc;
22 import java.io.BufferedOutputStream JavaDoc;
23 import java.io.ByteArrayOutputStream JavaDoc;
24 import java.io.EOFException JavaDoc;
25 import java.io.FileInputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.OutputStreamWriter JavaDoc;
29
30 import java.lang.ref.SoftReference JavaDoc;
31
32 import java.net.Socket JavaDoc;
33
34 import java.security.NoSuchAlgorithmException JavaDoc;
35
36 import java.sql.SQLException JavaDoc;
37 import java.sql.SQLWarning JavaDoc;
38
39 import java.util.ArrayList JavaDoc;
40 import java.util.Properties JavaDoc;
41 import java.util.zip.Deflater JavaDoc;
42 import java.util.zip.Inflater JavaDoc;
43
44
45 /**
46  * This class is used by Connection for communicating with the MySQL server.
47  *
48  * @author Mark Matthews
49  * @version $Id: MysqlIO.java,v 1.32.2.46 2004/02/06 00:54:42 mmatthew Exp $
50  *
51  * @see java.sql.Connection
52  */

53 public class MysqlIO {
54     static final int NULL_LENGTH = ~0;
55     static final int COMP_HEADER_LENGTH = 3;
56     static final int MIN_COMPRESS_LEN = 50;
57     static final int HEADER_LENGTH = 4;
58     private static int maxBufferSize = 65535;
59     private static final int CLIENT_COMPRESS = 32; /* Can use compression
60     protcol */

61     private static final int CLIENT_CONNECT_WITH_DB = 8;
62     private static final int CLIENT_FOUND_ROWS = 2;
63     private static final int CLIENT_IGNORE_SPACE = 256; /* Ignore spaces
64     before '(' */

65     private static final int CLIENT_LOCAL_FILES = 128; /* Can use LOAD DATA
66     LOCAL */

67
68     /* Found instead of
69        affected rows */

70     private static final int CLIENT_LONG_FLAG = 4; /* Get all column flags */
71     private static final int CLIENT_LONG_PASSWORD = 1; /* new more secure
72     passwords */

73     private static final int CLIENT_PROTOCOL_41 = 512; // for > 4.1.1
74
private static final int CLIENT_INTERACTIVE = 1024;
75     private static final int CLIENT_SSL = 2048;
76     private static final int CLIENT_RESERVED = 16384; // for 4.1.0 only
77
private static final int CLIENT_SECURE_CONNECTION = 32768;
78     private static final String JavaDoc FALSE_SCRAMBLE = "xxxxxxxx";
79
80     /**
81      * We store the platform 'encoding' here, only used to avoid munging
82      * filenames for LOAD DATA LOCAL INFILE...
83      */

84     private static String JavaDoc jvmPlatformCharset = null;
85
86     static {
87         OutputStreamWriter JavaDoc outWriter = null;
88
89         //
90
// Use the I/O system to get the encoding (if possible), to avoid
91
// security restrictions on System.getProperty("file.encoding") in
92
// applets (why is that restricted?)
93
//
94
try {
95             outWriter = new OutputStreamWriter JavaDoc(new ByteArrayOutputStream JavaDoc());
96             jvmPlatformCharset = outWriter.getEncoding();
97         } finally {
98             try {
99                 outWriter.close();
100             } catch (IOException JavaDoc ioEx) {
101                 // ignore
102
}
103         }
104     }
105
106     //
107
// Use this when reading in rows to avoid thousands of new()
108
// calls, because the byte arrays just get copied out of the
109
// packet anyway
110
//
111
private Buffer reusablePacket = null;
112     private Buffer sendPacket = null;
113     private Buffer sharedSendPacket = null;
114
115     /** Data to the server */
116
117     //private DataOutputStream _Mysql_Output = null;
118
private BufferedOutputStream JavaDoc mysqlOutput = null;
119     private com.mysql.jdbc.Connection connection;
120     private Deflater JavaDoc deflater = null;
121     private Inflater JavaDoc inflater = null;
122
123     /** Buffered data from the server */
124
125     //private BufferedInputStream _Mysql_Buf_Input = null;
126

127     /** Buffered data to the server */
128
129     //private BufferedOutputStream _Mysql_Buf_Output = null;
130

131     /** Data from the server */
132
133     //private DataInputStream _Mysql_Input = null;
134
private InputStream JavaDoc mysqlInput = null;
135     private RowData streamingData = null;
136
137     //
138
// For SQL Warnings
139
//
140
private SQLWarning JavaDoc warningChain = null;
141
142     /** The connection to the server */
143     private Socket JavaDoc mysqlConnection = null;
144     private SocketFactory socketFactory = null;
145
146     //
147
// Packet used for 'LOAD DATA LOCAL INFILE'
148
//
149
// We use a SoftReference, so that we don't penalize intermittent
150
// use of this feature
151
//
152
private SoftReference JavaDoc loadFileBufRef;
153
154     //
155
// Used to send large packets to the server versions 4+
156
// We use a SoftReference, so that we don't penalize intermittent
157
// use of this feature
158
//
159
private SoftReference JavaDoc splitBufRef;
160     private String JavaDoc host = null;
161     private String JavaDoc seed;
162     private String JavaDoc serverVersion = null;
163     private String JavaDoc socketFactoryClassName = null;
164     private byte[] packetHeaderBuf = new byte[4];
165     private boolean clearStreamBeforeEachQuery = false;
166     private boolean colDecimalNeedsBump = false; // do we need to increment the colDecimal flag?
167
private boolean has41NewNewProt = false;
168
169     /** Does the server support long column info? */
170     private boolean hasLongColumnInfo = false;
171     private boolean isInteractiveClient = false;
172
173     /**
174      * Does the character set of this connection match the character set of the
175      * platform
176      */

177     private boolean platformDbCharsetMatches = true;
178     private boolean profileSql = false;
179
180     /** Should we use 4.1 protocol extensions? */
181     private boolean use41Extensions = false;
182     private boolean useCompression = false;
183     private boolean useNewLargePackets = false;
184     private boolean useNewUpdateCounts = false; // should we use the new larger update counts?
185
private byte packetSequence = 0;
186     private byte protocolVersion = 0;
187     private int clientParam = 0;
188
189     // changed once we've connected.
190
private int maxAllowedPacket = 1024 * 1024;
191     private int maxThreeBytes = 255 * 255 * 255;
192     private int port = 3306;
193     private int serverMajorVersion = 0;
194     private int serverMinorVersion = 0;
195     private int serverSubMinorVersion = 0;
196
197     /**
198      * Constructor: Connect to the MySQL server and setup a stream connection.
199      *
200      * @param host the hostname to connect to
201      * @param port the port number that the server is listening on
202      * @param socketFactoryClassName the socket factory to use
203      * @param props the Properties from DriverManager.getConnection()
204      * @param conn the Connection that is creating us
205      * @param socketTimeout the timeout to set for the socket (0 means no
206      * timeout)
207      *
208      * @throws IOException if an IOException occurs during connect.
209      * @throws java.sql.SQLException if a database access error occurs.
210      */

211     protected MysqlIO(String JavaDoc host, int port, String JavaDoc socketFactoryClassName,
212         Properties JavaDoc props, com.mysql.jdbc.Connection conn, int socketTimeout)
213         throws IOException JavaDoc, java.sql.SQLException JavaDoc {
214         this.connection = conn;
215         this.reusablePacket = new Buffer(this.connection.getNetBufferLength());
216         this.port = port;
217         this.host = host;
218         this.socketFactoryClassName = socketFactoryClassName;
219         this.socketFactory = createSocketFactory();
220         this.mysqlConnection = socketFactory.connect(this.host, props);
221         this.clearStreamBeforeEachQuery = this.connection.alwaysClearStream();
222
223         if (socketTimeout != 0) {
224             try {
225                 this.mysqlConnection.setSoTimeout(socketTimeout);
226             } catch (Exception JavaDoc ex) {
227                 /* Ignore if the platform does not support it */
228             }
229         }
230
231         this.mysqlConnection = this.socketFactory.beforeHandshake();
232
233         if (!this.connection.isUsingUnbufferedInput()) {
234             this.mysqlInput = new BufferedInputStream JavaDoc(this.mysqlConnection
235                     .getInputStream(), 16384);
236         } else {
237             this.mysqlInput = this.mysqlConnection.getInputStream();
238         }
239
240         this.mysqlOutput = new BufferedOutputStream JavaDoc(this.mysqlConnection
241                 .getOutputStream(), 16384);
242         this.isInteractiveClient = this.connection.isInteractiveClient();
243     }
244
245     /**
246      * Should the driver generate SQL statement profiles?
247      *
248      * @param flag should the driver enable profiling?
249      */

250     protected void setProfileSql(boolean flag) {
251         this.profileSql = flag;
252     }
253
254     /**
255      * Build a result set. Delegates to buildResultSetWithRows() to build a
256      * JDBC-version-specific ResultSet, given rows as byte data, and field
257      * information.
258      *
259      * @param columnCount the number of columns in the result set
260      * @param maxRows the maximum number of rows to read (-1 means all rows)
261      * @param resultSetType the type of result set (CONCUR_UPDATABLE or
262      * READ_ONLY)
263      * @param streamResults should the result set be read all at once, or
264      * streamed?
265      * @param catalog the database name in use when the result set was created
266      *
267      * @return a result set
268      *
269      * @throws Exception if a database access error occurs
270      */

271     protected ResultSet getResultSet(long columnCount, int maxRows,
272         int resultSetType, boolean streamResults, String JavaDoc catalog)
273         throws Exception JavaDoc {
274         Buffer packet; // The packet from the server
275
Field[] fields = new Field[(int) columnCount];
276
277         // Read in the column information
278
for (int i = 0; i < columnCount; i++) {
279             packet = readPacket();
280             fields[i] = unpackField(packet, false);
281         }
282
283         packet = reuseAndReadPacket(this.reusablePacket);
284
285         RowData rowData = null;
286
287         if (!streamResults) {
288             ArrayList JavaDoc rows = new ArrayList JavaDoc();
289
290             // Now read the data
291
byte[][] rowBytes = nextRow((int) columnCount);
292             int rowCount = 0;
293
294             if (rowBytes != null) {
295                 rows.add(rowBytes);
296                 rowCount = 1;
297             }
298
299             while ((rowBytes != null) && (rowCount < maxRows)) {
300                 rowBytes = nextRow((int) columnCount);
301
302                 if (rowBytes != null) {
303                     rows.add(rowBytes);
304                     rowCount++;
305                 } else {
306                     if (Driver.TRACE) {
307                         Debug.msg(this, "* NULL Row *");
308                     }
309                 }
310             }
311
312             //
313
// Clear any outstanding data left on the wire
314
// when we've artifically limited the number of
315
// rows we retrieve (fix for BUG#1695)
316
//
317
if (rowCount <= maxRows) {
318                 clearInputStream();
319             }
320
321             if (Driver.TRACE) {
322                 Debug.msg(this,
323                     "* Fetched " + rows.size() + " rows from server *");
324             }
325
326             rowData = new RowDataStatic(rows);
327             reclaimLargeReusablePacket();
328         } else {
329             rowData = new RowDataDynamic(this, (int) columnCount);
330             this.streamingData = rowData;
331         }
332
333         return buildResultSetWithRows(catalog, fields, rowData, resultSetType);
334     }
335
336     /**
337      * Forcibly closes the underlying socket to MySQL.
338      */

339     protected final void forceClose() {
340         try {
341             if (this.mysqlInput != null) {
342                 this.mysqlInput.close();
343             }
344         } catch (IOException JavaDoc ioEx) {
345             // we can't do anything constructive about this
346
// Let the JVM clean it up later
347
this.mysqlInput = null;
348         }
349
350         try {
351             if (this.mysqlOutput != null) {
352                 this.mysqlOutput.close();
353             }
354         } catch (IOException JavaDoc ioEx) {
355             // we can't do anything constructive about this
356
// Let the JVM clean it up later
357
this.mysqlOutput = null;
358         }
359
360         try {
361             if (this.mysqlConnection != null) {
362                 this.mysqlConnection.close();
363             }
364         } catch (IOException JavaDoc ioEx) {
365             // we can't do anything constructive about this
366
// Let the JVM clean it up later
367
this.mysqlConnection = null;
368         }
369     }
370
371     /**
372      * Does the server send back extra column info?
373      *
374      * @return true if so
375      */

376     protected boolean hasLongColumnInfo() {
377         return this.hasLongColumnInfo;
378     }
379
380     /**
381      * Unpacks the Field information from the given packet. Understands pre 4.1
382      * and post 4.1 server version field packet structures.
383      *
384      * @param packet the packet containing the field information
385      * @param extractDefaultValues should default values be extracted?
386      *
387      * @return the unpacked field
388      */

389     protected final Field unpackField(Buffer packet,
390         boolean extractDefaultValues) {
391         if (this.use41Extensions) {
392             // we only store the position of the string and
393
// materialize only if needed...
394
if (this.has41NewNewProt) {
395                 int catalogNameStart = packet.getPosition() + 1;
396                 int catalogNameLength = packet.fastSkipLenString();
397             }
398
399             int databaseNameStart = packet.getPosition() + 1;
400             int databaseNameLength = packet.fastSkipLenString();
401
402             int tableNameStart = packet.getPosition() + 1;
403             int tableNameLength = packet.fastSkipLenString();
404
405             // orgTableName is never used so skip
406
int originalTableNameStart = packet.getPosition() + 1;
407             int originalTableNameLength = packet.fastSkipLenString();
408
409             // we only store the position again...
410
int nameStart = packet.getPosition() + 1;
411             int nameLength = packet.fastSkipLenString();
412
413             // orgColName is not required so skip...
414
int originalColumnNameStart = packet.getPosition() + 1;
415             int originalColumnNameLength = packet.fastSkipLenString();
416
417             packet.readByte();
418
419             int charSetNumber = packet.readInt();
420
421             int colLength = 0;
422
423             if (this.has41NewNewProt) {
424                 // fixme
425
colLength = (int) packet.readLong();
426             } else {
427                 colLength = packet.readLongInt();
428             }
429
430             int colType = packet.readByte() & 0xff;
431
432             short colFlag = 0;
433
434             if (this.hasLongColumnInfo) {
435                 colFlag = (short) (packet.readInt());
436             } else {
437                 colFlag = (short) (packet.readByte() & 0xff);
438             }
439
440             int colDecimals = packet.readByte() & 0xff;
441
442             int defaultValueStart = -1;
443             int defaultValueLength = -1;
444
445             if (extractDefaultValues) {
446                 defaultValueStart = packet.getPosition() + 1;
447                 defaultValueLength = packet.fastSkipLenString();
448             }
449
450             Field field = new Field(this.connection, packet.getByteBuffer(),
451                     databaseNameStart, databaseNameLength, tableNameStart,
452                     tableNameLength, originalTableNameStart,
453                     originalTableNameLength, nameStart, nameLength,
454                     originalColumnNameStart, originalColumnNameLength,
455                     colLength, colType, colFlag, colDecimals,
456                     defaultValueStart, defaultValueLength, charSetNumber);
457
458             return field;
459         } else {
460             int tableNameStart = packet.getPosition() + 1;
461             int tableNameLength = packet.fastSkipLenString();
462             int nameStart = packet.getPosition() + 1;
463             int nameLength = packet.fastSkipLenString();
464             int colLength = packet.readnBytes();
465             int colType = packet.readnBytes();
466             packet.readByte(); // We know it's currently 2
467

468             short colFlag = 0;
469
470             if (this.hasLongColumnInfo) {
471                 colFlag = (short) (packet.readInt());
472             } else {
473                 colFlag = (short) (packet.readByte() & 0xff);
474             }
475
476             int colDecimals = (packet.readByte() & 0xff);
477
478             if (this.colDecimalNeedsBump) {
479                 colDecimals++;
480             }
481
482             Field field = new Field(this.connection, packet.getBufferSource(),
483                     nameStart, nameLength, tableNameStart, tableNameLength,
484                     colLength, colType, colFlag, colDecimals);
485
486             return field;
487         }
488     }
489
490     /**
491      * Determines if the database charset is the same as the platform charset
492      */

493     protected void checkForCharsetMismatch() {
494         if (this.connection.useUnicode()
495                 && (this.connection.getEncoding() != null)) {
496             String JavaDoc encodingToCheck = jvmPlatformCharset;
497
498             if (encodingToCheck == null) {
499                 encodingToCheck = System.getProperty("file.encoding");
500             }
501
502             if (encodingToCheck == null) {
503                 this.platformDbCharsetMatches = false;
504             } else {
505                 this.platformDbCharsetMatches = encodingToCheck.equals(this.connection
506                         .getEncoding());
507             }
508         }
509     }
510
511     static int getMaxBuf() {
512         return maxBufferSize;
513     }
514
515     /**
516      * Get the major version of the MySQL server we are talking to.
517      *
518      * @return DOCUMENT ME!
519      */

520     final int getServerMajorVersion() {
521         return this.serverMajorVersion;
522     }
523
524     /**
525      * Get the minor version of the MySQL server we are talking to.
526      *
527      * @return DOCUMENT ME!
528      */

529     final int getServerMinorVersion() {
530         return this.serverMinorVersion;
531     }
532
533     /**
534      * Get the sub-minor version of the MySQL server we are talking to.
535      *
536      * @return DOCUMENT ME!
537      */

538     final int getServerSubMinorVersion() {
539         return this.serverSubMinorVersion;
540     }
541
542     /**
543      * Get the version string of the server we are talking to
544      *
545      * @return DOCUMENT ME!
546      */

547     String JavaDoc getServerVersion() {
548         return this.serverVersion;
549     }
550
551     /**
552      * Initialize communications with the MySQL server. Handles logging on, and
553      * handling initial connection errors.
554      *
555      * @param user DOCUMENT ME!
556      * @param password DOCUMENT ME!
557      * @param database DOCUMENT ME!
558      *
559      * @throws java.sql.SQLException DOCUMENT ME!
560      * @throws SQLException DOCUMENT ME!
561      */

562     void doHandshake(String JavaDoc user, String JavaDoc password, String JavaDoc database)
563         throws java.sql.SQLException JavaDoc {
564         // Read the first packet
565
Buffer buf = readPacket();
566
567         // Get the protocol version
568
this.protocolVersion = buf.readByte();
569
570         if (this.protocolVersion == -1) {
571             try {
572                 this.mysqlConnection.close();
573             } catch (Exception JavaDoc e) {
574                 ; // ignore
575
}
576
577             int errno = 2000;
578
579             errno = buf.readInt();
580
581             String JavaDoc serverErrorMessage = buf.readString();
582
583             StringBuffer JavaDoc errorBuf = new StringBuffer JavaDoc(" message from server: \"");
584             errorBuf.append(serverErrorMessage);
585             errorBuf.append("\"");
586
587             String JavaDoc xOpen = SQLError.mysqlToXOpen(errno);
588
589             throw new SQLException JavaDoc(SQLError.get(xOpen) + ", "
590                 + errorBuf.toString(), xOpen, errno);
591         }
592
593         this.serverVersion = buf.readString();
594
595         // Parse the server version into major/minor/subminor
596
int point = this.serverVersion.indexOf(".");
597
598         if (point != -1) {
599             try {
600                 int n = Integer.parseInt(this.serverVersion.substring(0, point));
601                 this.serverMajorVersion = n;
602             } catch (NumberFormatException JavaDoc NFE1) {
603                 ;
604             }
605
606             String JavaDoc remaining = this.serverVersion.substring(point + 1,
607                     this.serverVersion.length());
608             point = remaining.indexOf(".");
609
610             if (point != -1) {
611                 try {
612                     int n = Integer.parseInt(remaining.substring(0, point));
613                     this.serverMinorVersion = n;
614                 } catch (NumberFormatException JavaDoc nfe) {
615                     ;
616                 }
617
618                 remaining = remaining.substring(point + 1, remaining.length());
619
620                 int pos = 0;
621
622                 while (pos < remaining.length()) {
623                     if ((remaining.charAt(pos) < '0')
624                             || (remaining.charAt(pos) > '9')) {
625                         break;
626                     }
627
628                     pos++;
629                 }
630
631                 try {
632                     int n = Integer.parseInt(remaining.substring(0, pos));
633                     this.serverSubMinorVersion = n;
634                 } catch (NumberFormatException JavaDoc nfe) {
635                     ;
636                 }
637             }
638         }
639
640         if (versionMeetsMinimum(4, 0, 8)) {
641             this.maxThreeBytes = (256 * 256 * 256) - 1;
642             this.useNewLargePackets = true;
643         } else {
644             this.maxThreeBytes = 255 * 255 * 255;
645             this.useNewLargePackets = false;
646         }
647
648         this.colDecimalNeedsBump = versionMeetsMinimum(3, 23, 0);
649         this.colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15); // guess? Not noted in changelog
650
this.useNewUpdateCounts = versionMeetsMinimum(3, 22, 5);
651
652         long threadId = buf.readLong();
653         seed = buf.readString();
654
655         if (Driver.TRACE) {
656             Debug.msg(this, "Protocol Version: " + (int) this.protocolVersion);
657             Debug.msg(this, "Server Version: " + this.serverVersion);
658             Debug.msg(this, "Thread ID: " + threadId);
659             Debug.msg(this, "Crypt Seed: " + seed);
660         }
661
662         int serverCapabilities = 0;
663
664         if (buf.getPosition() < buf.getBufLength()) {
665             serverCapabilities = buf.readInt();
666         }
667
668         if (versionMeetsMinimum(4, 1, 1)) {
669             int position = buf.getPosition();
670
671             /* New protocol with 16 bytes to describe server characteristics */
672             int serverLanguage = buf.readInt(); // 2 bytes
673
buf.readInt();
674             buf.setPosition(position + 16);
675
676             String JavaDoc seedPart2 = buf.readString();
677             StringBuffer JavaDoc newSeed = new StringBuffer JavaDoc(20);
678             newSeed.append(seed);
679             newSeed.append(seedPart2);
680             this.seed = newSeed.toString();
681         }
682
683         if (((serverCapabilities & CLIENT_COMPRESS) != 0)
684                 && this.connection.useCompression()) {
685             clientParam |= CLIENT_COMPRESS;
686         }
687
688         if ((database != null) && (database.length() > 0)) {
689             clientParam |= CLIENT_CONNECT_WITH_DB;
690         }
691
692         if (((serverCapabilities & CLIENT_SSL) == 0)
693                 && this.connection.useSSL()) {
694             this.connection.setUseSSL(false);
695         }
696
697         if ((serverCapabilities & CLIENT_LONG_FLAG) != 0) {
698             // We understand other column flags, as well
699
clientParam |= CLIENT_LONG_FLAG;
700             this.hasLongColumnInfo = true;
701         }
702
703         // return FOUND rows
704
clientParam |= CLIENT_FOUND_ROWS;
705
706         if (this.connection.allowLoadLocalInfile()) {
707             clientParam |= CLIENT_LOCAL_FILES;
708         }
709
710         if (isInteractiveClient) {
711             clientParam |= CLIENT_INTERACTIVE;
712         }
713
714         // Authenticate
715
if (this.protocolVersion > 9) {
716             clientParam |= CLIENT_LONG_PASSWORD; // for long passwords
717
} else {
718             clientParam &= ~CLIENT_LONG_PASSWORD;
719         }
720
721         //
722
// 4.1 has some differences in the protocol
723
//
724
if (versionMeetsMinimum(4, 1, 0)) {
725             if (versionMeetsMinimum(4, 1, 1)) {
726                 clientParam |= CLIENT_PROTOCOL_41;
727                 this.has41NewNewProt = true;
728             } else {
729                 clientParam |= CLIENT_RESERVED;
730                 this.has41NewNewProt = false;
731             }
732
733             this.use41Extensions = true;
734         }
735
736         int passwordLength = 16;
737         int userLength = 0;
738         int databaseLength = 0;
739
740         if (user != null) {
741             userLength = user.length();
742         }
743
744         if (database != null) {
745             databaseLength = database.length();
746         }
747
748         int packLength = (userLength + passwordLength + databaseLength) + 7
749             + HEADER_LENGTH;
750         Buffer packet = null;
751
752         if (!connection.useSSL()) {
753             if ((serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
754                 clientParam |= CLIENT_SECURE_CONNECTION;
755
756                 if (versionMeetsMinimum(4, 1, 1)) {
757                     secureAuth411(packLength, serverCapabilities, clientParam,
758                         user, password, database);
759                 } else {
760                     secureAuth(packLength, serverCapabilities, clientParam,
761                         user, password, database);
762                 }
763             } else {
764                 packet = new Buffer(packLength);
765
766                 if ((clientParam & CLIENT_RESERVED) != 0) {
767                     if (versionMeetsMinimum(4, 1, 1)) {
768                         packet.writeLong(clientParam);
769                         packet.writeLong(this.maxThreeBytes);
770
771                         // charset, JDBC will connect as 'latin1',
772
// and use 'SET NAMES' to change to the desired
773
// charset after the connection is established.
774
packet.writeByte((byte) 8);
775
776                         // Set of bytes reserved for future use.
777
packet.writeBytesNoNull(new byte[23]);
778                     } else {
779                         packet.writeLong(clientParam);
780                         packet.writeLong(this.maxThreeBytes);
781                     }
782                 } else {
783                     packet.writeInt((int) clientParam);
784                     packet.writeLongInt(this.maxThreeBytes);
785                 }
786
787                 // User/Password data
788
packet.writeString(user);
789
790                 if (this.protocolVersion > 9) {
791                     packet.writeString(Util.newCrypt(password, this.seed));
792                 } else {
793                     packet.writeString(Util.oldCrypt(password, this.seed));
794                 }
795
796                 if (((serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0)
797                         && (database != null) && (database.length() > 0)) {
798                     packet.writeString(database);
799                 }
800
801                 send(packet);
802             }
803         } else {
804             boolean doSecureAuth = false;
805
806             if ((serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
807                 clientParam |= CLIENT_SECURE_CONNECTION;
808                 doSecureAuth = true;
809             }
810
811             clientParam |= CLIENT_SSL;
812             packet = new Buffer(packLength);
813
814             if ((clientParam & CLIENT_RESERVED) != 0) {
815                 packet.writeLong(clientParam);
816             } else {
817                 packet.writeInt((int) clientParam);
818             }
819
820             send(packet);
821
822             javax.net.ssl.SSLSocketFactory sslFact = (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory
823                 .getDefault();
824
825             try {
826                 this.mysqlConnection = sslFact.createSocket(this.mysqlConnection,
827