Source Code Cross Referenced for MysqlIO.java in  » Database-JDBC-Connection-Pool » mysql-connector-java-5.1.3 » com » mysql » jdbc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » mysql connector java 5.1.3 » com.mysql.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:              Copyright (C) 2002-2007 MySQL AB
0003:
0004:              This program is free software; you can redistribute it and/or modify
0005:              it under the terms of version 2 of the GNU General Public License as
0006:              published by the Free Software Foundation.
0007:
0008:              There are special exceptions to the terms and conditions of the GPL
0009:              as it is applied to this software. View the full text of the
0010:              exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
0011:              software distribution.
0012:
0013:              This program is distributed in the hope that it will be useful,
0014:              but WITHOUT ANY WARRANTY; without even the implied warranty of
0015:              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016:              GNU General Public License for more details.
0017:
0018:              You should have received a copy of the GNU General Public License
0019:              along with this program; if not, write to the Free Software
0020:              Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0021:
0022:
0023:
0024:         */
0025:        package com.mysql.jdbc;
0026:
0027:        import java.io.BufferedInputStream;
0028:        import java.io.BufferedOutputStream;
0029:        import java.io.ByteArrayOutputStream;
0030:        import java.io.EOFException;
0031:        import java.io.FileInputStream;
0032:        import java.io.IOException;
0033:        import java.io.InputStream;
0034:        import java.io.OutputStreamWriter;
0035:        import java.lang.ref.SoftReference;
0036:        import java.math.BigInteger;
0037:        import java.net.MalformedURLException;
0038:        import java.net.Socket;
0039:        import java.net.URL;
0040:        import java.security.NoSuchAlgorithmException;
0041:        import java.sql.ResultSet;
0042:        import java.sql.SQLException;
0043:        import java.sql.Types;
0044:        import java.util.ArrayList;
0045:        import java.util.Calendar;
0046:        import java.util.Iterator;
0047:        import java.util.LinkedList;
0048:        import java.util.List;
0049:        import java.util.Properties;
0050:        import java.util.zip.Deflater;
0051:
0052:        import com.mysql.jdbc.profiler.ProfileEventSink;
0053:        import com.mysql.jdbc.profiler.ProfilerEvent;
0054:        import com.mysql.jdbc.util.ReadAheadInputStream;
0055:        import com.mysql.jdbc.util.ResultSetUtil;
0056:
0057:        /**
0058:         * This class is used by Connection for communicating with the MySQL server.
0059:         *
0060:         * @author Mark Matthews
0061:         * @version $Id: MysqlIO.java 6496 2007-08-13 20:22:33Z mmatthews $
0062:         *
0063:         * @see java.sql.Connection
0064:         */
0065:        class MysqlIO {
0066:            private static final int UTF8_CHARSET_INDEX = 33;
0067:            private static final String CODE_PAGE_1252 = "Cp1252";
0068:            protected static final int NULL_LENGTH = ~0;
0069:            protected static final int COMP_HEADER_LENGTH = 3;
0070:            protected static final int MIN_COMPRESS_LEN = 50;
0071:            protected static final int HEADER_LENGTH = 4;
0072:            protected static final int AUTH_411_OVERHEAD = 33;
0073:            private static int maxBufferSize = 65535;
0074:            private static final int CLIENT_COMPRESS = 32; /* Can use compression
0075:               protcol */
0076:            protected static final int CLIENT_CONNECT_WITH_DB = 8;
0077:            private static final int CLIENT_FOUND_ROWS = 2;
0078:            private static final int CLIENT_LOCAL_FILES = 128; /* Can use LOAD DATA
0079:               LOCAL */
0080:
0081:            /* Found instead of
0082:               affected rows */
0083:            private static final int CLIENT_LONG_FLAG = 4; /* Get all column flags */
0084:            private static final int CLIENT_LONG_PASSWORD = 1; /* new more secure
0085:               passwords */
0086:            private static final int CLIENT_PROTOCOL_41 = 512; // for > 4.1.1
0087:            private static final int CLIENT_INTERACTIVE = 1024;
0088:            protected static final int CLIENT_SSL = 2048;
0089:            private static final int CLIENT_TRANSACTIONS = 8192; // Client knows about transactions
0090:            protected static final int CLIENT_RESERVED = 16384; // for 4.1.0 only
0091:            protected static final int CLIENT_SECURE_CONNECTION = 32768;
0092:            private static final int CLIENT_MULTI_QUERIES = 65536; // Enable/disable multiquery support
0093:            private static final int CLIENT_MULTI_RESULTS = 131072; // Enable/disable multi-results
0094:            private static final int SERVER_STATUS_IN_TRANS = 1;
0095:            private static final int SERVER_STATUS_AUTOCOMMIT = 2; // Server in auto_commit mode
0096:            private static final int SERVER_MORE_RESULTS_EXISTS = 8; // Multi query - next query exists
0097:            private static final int SERVER_QUERY_NO_GOOD_INDEX_USED = 16;
0098:            private static final int SERVER_QUERY_NO_INDEX_USED = 32;
0099:            private static final int SERVER_STATUS_CURSOR_EXISTS = 64;
0100:            private static final String FALSE_SCRAMBLE = "xxxxxxxx"; //$NON-NLS-1$
0101:            protected static final int MAX_QUERY_SIZE_TO_LOG = 1024; // truncate logging of queries at 1K
0102:            protected static final int MAX_QUERY_SIZE_TO_EXPLAIN = 1024 * 1024; // don't explain queries above 1MB
0103:            protected static final int INITIAL_PACKET_SIZE = 1024;
0104:            /**
0105:             * We store the platform 'encoding' here, only used to avoid munging
0106:             * filenames for LOAD DATA LOCAL INFILE...
0107:             */
0108:            private static String jvmPlatformCharset = null;
0109:
0110:            /**
0111:             * We need to have a 'marker' for all-zero datetimes so that ResultSet
0112:             * can decide what to do based on connection setting
0113:             */
0114:            protected final static String ZERO_DATE_VALUE_MARKER = "0000-00-00";
0115:            protected final static String ZERO_DATETIME_VALUE_MARKER = "0000-00-00 00:00:00";
0116:
0117:            static {
0118:                OutputStreamWriter outWriter = null;
0119:
0120:                //
0121:                // Use the I/O system to get the encoding (if possible), to avoid
0122:                // security restrictions on System.getProperty("file.encoding") in
0123:                // applets (why is that restricted?)
0124:                //
0125:                try {
0126:                    outWriter = new OutputStreamWriter(
0127:                            new ByteArrayOutputStream());
0128:                    jvmPlatformCharset = outWriter.getEncoding();
0129:                } finally {
0130:                    try {
0131:                        if (outWriter != null) {
0132:                            outWriter.close();
0133:                        }
0134:                    } catch (IOException ioEx) {
0135:                        // ignore
0136:                    }
0137:                }
0138:            }
0139:
0140:            /** Max number of bytes to dump when tracing the protocol */
0141:            private final static int MAX_PACKET_DUMP_LENGTH = 1024;
0142:            private boolean packetSequenceReset = false;
0143:            protected int serverCharsetIndex;
0144:
0145:            //
0146:            // Use this when reading in rows to avoid thousands of new()
0147:            // calls, because the byte arrays just get copied out of the
0148:            // packet anyway
0149:            //
0150:            private Buffer reusablePacket = null;
0151:            private Buffer sendPacket = null;
0152:            private Buffer sharedSendPacket = null;
0153:
0154:            /** Data to the server */
0155:            protected BufferedOutputStream mysqlOutput = null;
0156:            protected ConnectionImpl connection;
0157:            private Deflater deflater = null;
0158:            protected InputStream mysqlInput = null;
0159:            private LinkedList packetDebugRingBuffer = null;
0160:            private RowData streamingData = null;
0161:
0162:            /** The connection to the server */
0163:            protected Socket mysqlConnection = null;
0164:            private SocketFactory socketFactory = null;
0165:
0166:            //
0167:            // Packet used for 'LOAD DATA LOCAL INFILE'
0168:            //
0169:            // We use a SoftReference, so that we don't penalize intermittent
0170:            // use of this feature
0171:            //
0172:            private SoftReference loadFileBufRef;
0173:
0174:            //
0175:            // Used to send large packets to the server versions 4+
0176:            // We use a SoftReference, so that we don't penalize intermittent
0177:            // use of this feature
0178:            //
0179:            private SoftReference splitBufRef;
0180:            protected String host = null;
0181:            protected String seed;
0182:            private String serverVersion = null;
0183:            private String socketFactoryClassName = null;
0184:            private byte[] packetHeaderBuf = new byte[4];
0185:            private boolean colDecimalNeedsBump = false; // do we need to increment the colDecimal flag?
0186:            private boolean hadWarnings = false;
0187:            private boolean has41NewNewProt = false;
0188:
0189:            /** Does the server support long column info? */
0190:            private boolean hasLongColumnInfo = false;
0191:            private boolean isInteractiveClient = false;
0192:            private boolean logSlowQueries = false;
0193:
0194:            /**
0195:             * Does the character set of this connection match the character set of the
0196:             * platform
0197:             */
0198:            private boolean platformDbCharsetMatches = true; // changed once we've connected.
0199:            private boolean profileSql = false;
0200:            private boolean queryBadIndexUsed = false;
0201:            private boolean queryNoIndexUsed = false;
0202:
0203:            /** Should we use 4.1 protocol extensions? */
0204:            private boolean use41Extensions = false;
0205:            private boolean useCompression = false;
0206:            private boolean useNewLargePackets = false;
0207:            private boolean useNewUpdateCounts = false; // should we use the new larger update counts?
0208:            private byte packetSequence = 0;
0209:            private byte readPacketSequence = -1;
0210:            private boolean checkPacketSequence = false;
0211:            private byte protocolVersion = 0;
0212:            private int maxAllowedPacket = 1024 * 1024;
0213:            protected int maxThreeBytes = 255 * 255 * 255;
0214:            protected int port = 3306;
0215:            protected int serverCapabilities;
0216:            private int serverMajorVersion = 0;
0217:            private int serverMinorVersion = 0;
0218:            private int serverStatus = 0;
0219:            private int serverSubMinorVersion = 0;
0220:            private int warningCount = 0;
0221:            protected long clientParam = 0;
0222:            protected long lastPacketSentTimeMs = 0;
0223:            private boolean traceProtocol = false;
0224:            private boolean enablePacketDebug = false;
0225:            private Calendar sessionCalendar;
0226:            private boolean useConnectWithDb;
0227:            private boolean needToGrabQueryFromPacket;
0228:            private boolean autoGenerateTestcaseScript;
0229:            private long threadId;
0230:            private boolean useNanosForElapsedTime;
0231:            private long slowQueryThreshold;
0232:            private String queryTimingUnits;
0233:            private List statementInterceptors;
0234:            private boolean useDirectRowUnpack = true;
0235:            private int useBufferRowSizeThreshold;
0236:
0237:            /**
0238:             * Constructor:  Connect to the MySQL server and setup a stream connection.
0239:             *
0240:             * @param host the hostname to connect to
0241:             * @param port the port number that the server is listening on
0242:             * @param props the Properties from DriverManager.getConnection()
0243:             * @param socketFactoryClassName the socket factory to use
0244:             * @param conn the Connection that is creating us
0245:             * @param socketTimeout the timeout to set for the socket (0 means no
0246:             *        timeout)
0247:             *
0248:             * @throws IOException if an IOException occurs during connect.
0249:             * @throws SQLException if a database access error occurs.
0250:             */
0251:            public MysqlIO(String host, int port, Properties props,
0252:                    String socketFactoryClassName, ConnectionImpl conn,
0253:                    int socketTimeout, int useBufferRowSizeThreshold)
0254:                    throws IOException, SQLException {
0255:                this .connection = conn;
0256:
0257:                if (this .connection.getEnablePacketDebug()) {
0258:                    this .packetDebugRingBuffer = new LinkedList();
0259:                }
0260:
0261:                this .useBufferRowSizeThreshold = useBufferRowSizeThreshold;
0262:                this .useDirectRowUnpack = this .connection
0263:                        .getUseDirectRowUnpack();
0264:
0265:                this .logSlowQueries = this .connection.getLogSlowQueries();
0266:
0267:                this .reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
0268:                this .sendPacket = new Buffer(INITIAL_PACKET_SIZE);
0269:
0270:                this .port = port;
0271:                this .host = host;
0272:
0273:                this .socketFactoryClassName = socketFactoryClassName;
0274:                this .socketFactory = createSocketFactory();
0275:
0276:                this .mysqlConnection = this .socketFactory.connect(this .host,
0277:                        this .port, props);
0278:
0279:                if (socketTimeout != 0) {
0280:                    try {
0281:                        this .mysqlConnection.setSoTimeout(socketTimeout);
0282:                    } catch (Exception ex) {
0283:                        /* Ignore if the platform does not support it */
0284:                    }
0285:                }
0286:
0287:                this .mysqlConnection = this .socketFactory.beforeHandshake();
0288:
0289:                if (this .connection.getUseReadAheadInput()) {
0290:                    this .mysqlInput = new ReadAheadInputStream(
0291:                            this .mysqlConnection.getInputStream(), 16384,
0292:                            this .connection.getTraceProtocol(), this .connection
0293:                                    .getLog());
0294:                } else if (this .connection.useUnbufferedInput()) {
0295:                    this .mysqlInput = this .mysqlConnection.getInputStream();
0296:                } else {
0297:                    this .mysqlInput = new BufferedInputStream(
0298:                            this .mysqlConnection.getInputStream(), 16384);
0299:                }
0300:
0301:                this .mysqlOutput = new BufferedOutputStream(
0302:                        this .mysqlConnection.getOutputStream(), 16384);
0303:
0304:                this .isInteractiveClient = this .connection
0305:                        .getInteractiveClient();
0306:                this .profileSql = this .connection.getProfileSql();
0307:                this .sessionCalendar = Calendar.getInstance();
0308:                this .autoGenerateTestcaseScript = this .connection
0309:                        .getAutoGenerateTestcaseScript();
0310:
0311:                this .needToGrabQueryFromPacket = (this .profileSql
0312:                        || this .logSlowQueries || this .autoGenerateTestcaseScript);
0313:
0314:                if (this .connection.getUseNanosForElapsedTime()
0315:                        && Util.nanoTimeAvailable()) {
0316:                    this .useNanosForElapsedTime = true;
0317:
0318:                    this .queryTimingUnits = Messages.getString("Nanoseconds");
0319:                } else {
0320:                    this .queryTimingUnits = Messages.getString("Milliseconds");
0321:                }
0322:
0323:                if (this .connection.getLogSlowQueries()) {
0324:                    calculateSlowQueryThreshold();
0325:                }
0326:            }
0327:
0328:            protected void initializeStatementInterceptors(
0329:                    String interceptorClasses, Properties props)
0330:                    throws SQLException {
0331:                List interceptorsToCreate = StringUtils.split(
0332:                        interceptorClasses, ",", true);
0333:
0334:                this .statementInterceptors = new LinkedList();
0335:
0336:                Iterator iter = interceptorsToCreate.iterator();
0337:
0338:                String classname = null;
0339:
0340:                try {
0341:                    while (iter.hasNext()) {
0342:                        classname = iter.next().toString();
0343:                        StatementInterceptor interceptorInstance = (StatementInterceptor) Class
0344:                                .forName(classname).newInstance();
0345:                        interceptorInstance.init(this .connection, props);
0346:
0347:                        this .statementInterceptors.add(interceptorInstance);
0348:                    }
0349:                } catch (Throwable t) {
0350:                    SQLException sqlEx = SQLError.createSQLException(Messages
0351:                            .getString("MysqlIo.BadStatementInterceptor",
0352:                                    new Object[] { classname }));
0353:                    sqlEx.initCause(t);
0354:
0355:                    throw sqlEx;
0356:                }
0357:            }
0358:
0359:            /**
0360:             * Does the server send back extra column info?
0361:             *
0362:             * @return true if so
0363:             */
0364:            public boolean hasLongColumnInfo() {
0365:                return this .hasLongColumnInfo;
0366:            }
0367:
0368:            protected boolean isDataAvailable() throws SQLException {
0369:                try {
0370:                    return this .mysqlInput.available() > 0;
0371:                } catch (IOException ioEx) {
0372:                    throw SQLError.createCommunicationsException(
0373:                            this .connection, this .lastPacketSentTimeMs, ioEx);
0374:                }
0375:            }
0376:
0377:            /**
0378:             * DOCUMENT ME!
0379:             *
0380:             * @return Returns the lastPacketSentTimeMs.
0381:             */
0382:            protected long getLastPacketSentTimeMs() {
0383:                return this .lastPacketSentTimeMs;
0384:            }
0385:
0386:            /**
0387:             * Build a result set. Delegates to buildResultSetWithRows() to build a
0388:             * JDBC-version-specific ResultSet, given rows as byte data, and field
0389:             * information.
0390:             *
0391:             * @param callingStatement DOCUMENT ME!
0392:             * @param columnCount the number of columns in the result set
0393:             * @param maxRows the maximum number of rows to read (-1 means all rows)
0394:             * @param resultSetType (TYPE_FORWARD_ONLY, TYPE_SCROLL_????)
0395:             * @param resultSetConcurrency the type of result set (CONCUR_UPDATABLE or
0396:             *        READ_ONLY)
0397:             * @param streamResults should the result set be read all at once, or
0398:             *        streamed?
0399:             * @param catalog the database name in use when the result set was created
0400:             * @param isBinaryEncoded is this result set in native encoding?
0401:             * @param unpackFieldInfo should we read MYSQL_FIELD info (if available)?
0402:             *
0403:             * @return a result set
0404:             *
0405:             * @throws SQLException if a database access error occurs
0406:             */
0407:            protected ResultSetImpl getResultSet(
0408:                    StatementImpl callingStatement, long columnCount,
0409:                    int maxRows, int resultSetType, int resultSetConcurrency,
0410:                    boolean streamResults, String catalog,
0411:                    boolean isBinaryEncoded, Field[] metadataFromCache)
0412:                    throws SQLException {
0413:                Buffer packet; // The packet from the server
0414:                Field[] fields = null;
0415:
0416:                // Read in the column information
0417:
0418:                if (metadataFromCache == null /* we want the metadata from the server */) {
0419:                    fields = new Field[(int) columnCount];
0420:
0421:                    for (int i = 0; i < columnCount; i++) {
0422:                        Buffer fieldPacket = null;
0423:
0424:                        fieldPacket = readPacket();
0425:                        fields[i] = unpackField(fieldPacket, false);
0426:                    }
0427:                } else {
0428:                    for (int i = 0; i < columnCount; i++) {
0429:                        skipPacket();
0430:                    }
0431:                }
0432:
0433:                packet = reuseAndReadPacket(this .reusablePacket);
0434:
0435:                readServerStatusForResultSets(packet);
0436:
0437:                //
0438:                // Handle cursor-based fetch first
0439:                //
0440:
0441:                if (this .connection.versionMeetsMinimum(5, 0, 2)
0442:                        && this .connection.getUseCursorFetch()
0443:                        && isBinaryEncoded
0444:                        && callingStatement != null
0445:                        && callingStatement.getFetchSize() != 0
0446:                        && callingStatement.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
0447:                    ServerPreparedStatement prepStmt = (com.mysql.jdbc.ServerPreparedStatement) callingStatement;
0448:
0449:                    boolean usingCursor = true;
0450:
0451:                    //
0452:                    // Server versions 5.0.5 or newer will only open
0453:                    // a cursor and set this flag if they can, otherwise
0454:                    // they punt and go back to mysql_store_results() behavior
0455:                    //
0456:
0457:                    if (this .connection.versionMeetsMinimum(5, 0, 5)) {
0458:                        usingCursor = (this .serverStatus & SERVER_STATUS_CURSOR_EXISTS) != 0;
0459:                    }
0460:
0461:                    if (usingCursor) {
0462:                        RowData rows = new RowDataCursor(this , prepStmt, fields);
0463:
0464:                        ResultSetImpl rs = buildResultSetWithRows(
0465:                                callingStatement, catalog, fields, rows,
0466:                                resultSetType, resultSetConcurrency,
0467:                                isBinaryEncoded);
0468:
0469:                        if (usingCursor) {
0470:                            rs.setFetchSize(callingStatement.getFetchSize());
0471:                        }
0472:
0473:                        return rs;
0474:                    }
0475:                }
0476:
0477:                RowData rowData = null;
0478:
0479:                if (!streamResults) {
0480:                    rowData = readSingleRowSet(columnCount, maxRows,
0481:                            resultSetConcurrency, isBinaryEncoded,
0482:                            (metadataFromCache == null) ? fields
0483:                                    : metadataFromCache);
0484:                } else {
0485:                    rowData = new RowDataDynamic(this , (int) columnCount,
0486:                            (metadataFromCache == null) ? fields
0487:                                    : metadataFromCache, isBinaryEncoded);
0488:                    this .streamingData = rowData;
0489:                }
0490:
0491:                ResultSetImpl rs = buildResultSetWithRows(callingStatement,
0492:                        catalog, (metadataFromCache == null) ? fields
0493:                                : metadataFromCache, rowData, resultSetType,
0494:                        resultSetConcurrency, isBinaryEncoded);
0495:
0496:                return rs;
0497:            }
0498:
0499:            /**
0500:             * Forcibly closes the underlying socket to MySQL.
0501:             */
0502:            protected final void forceClose() {
0503:                try {
0504:                    if (this .mysqlInput != null) {
0505:                        this .mysqlInput.close();
0506:                    }
0507:                } catch (IOException ioEx) {
0508:                    // we can't do anything constructive about this
0509:                    // Let the JVM clean it up later
0510:                    this .mysqlInput = null;
0511:                }
0512:
0513:                try {
0514:                    if (this .mysqlOutput != null) {
0515:                        this .mysqlOutput.close();
0516:                    }
0517:                } catch (IOException ioEx) {
0518:                    // we can't do anything constructive about this
0519:                    // Let the JVM clean it up later
0520:                    this .mysqlOutput = null;
0521:                }
0522:
0523:                try {
0524:                    if (this .mysqlConnection != null) {
0525:                        this .mysqlConnection.close();
0526:                    }
0527:                } catch (IOException ioEx) {
0528:                    // we can't do anything constructive about this
0529:                    // Let the JVM clean it up later
0530:                    this .mysqlConnection = null;
0531:                }
0532:            }
0533:
0534:            /**
0535:             * Reads and discards a single MySQL packet from the input stream.
0536:             *
0537:             * @throws SQLException if the network fails while skipping the
0538:             * packet.
0539:             */
0540:            protected final void skipPacket() throws SQLException {
0541:                try {
0542:
0543:                    int lengthRead = readFully(this .mysqlInput,
0544:                            this .packetHeaderBuf, 0, 4);
0545:
0546:                    if (lengthRead < 4) {
0547:                        forceClose();
0548:                        throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$
0549:                    }
0550:
0551:                    int packetLength = (this .packetHeaderBuf[0] & 0xff)
0552:                            + ((this .packetHeaderBuf[1] & 0xff) << 8)
0553:                            + ((this .packetHeaderBuf[2] & 0xff) << 16);
0554:
0555:                    if (this .traceProtocol) {
0556:                        StringBuffer traceMessageBuf = new StringBuffer();
0557:
0558:                        traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$
0559:                        traceMessageBuf.append(packetLength);
0560:                        traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$
0561:                        traceMessageBuf.append(StringUtils.dumpAsHex(
0562:                                this .packetHeaderBuf, 4));
0563:
0564:                        this .connection.getLog().logTrace(
0565:                                traceMessageBuf.toString());
0566:                    }
0567:
0568:                    byte multiPacketSeq = this .packetHeaderBuf[3];
0569:
0570:                    if (!this .packetSequenceReset) {
0571:                        if (this .enablePacketDebug && this .checkPacketSequence) {
0572:                            checkPacketSequencing(multiPacketSeq);
0573:                        }
0574:                    } else {
0575:                        this .packetSequenceReset = false;
0576:                    }
0577:
0578:                    this .readPacketSequence = multiPacketSeq;
0579:
0580:                    skipFully(this .mysqlInput, packetLength);
0581:                } catch (IOException ioEx) {
0582:                    throw SQLError.createCommunicationsException(
0583:                            this .connection, this .lastPacketSentTimeMs, ioEx);
0584:                } catch (OutOfMemoryError oom) {
0585:                    try {
0586:                        this .connection.realClose(false, false, true, oom);
0587:                    } finally {
0588:                        throw oom;
0589:                    }
0590:                }
0591:            }
0592:
0593:            /**
0594:             * Read one packet from the MySQL server
0595:             *
0596:             * @return the packet from the server.
0597:             *
0598:             * @throws SQLException DOCUMENT ME!
0599:             * @throws CommunicationsException DOCUMENT ME!
0600:             */
0601:            protected final Buffer readPacket() throws SQLException {
0602:                try {
0603:
0604:                    int lengthRead = readFully(this .mysqlInput,
0605:                            this .packetHeaderBuf, 0, 4);
0606:
0607:                    if (lengthRead < 4) {
0608:                        forceClose();
0609:                        throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$
0610:                    }
0611:
0612:                    int packetLength = (this .packetHeaderBuf[0] & 0xff)
0613:                            + ((this .packetHeaderBuf[1] & 0xff) << 8)
0614:                            + ((this .packetHeaderBuf[2] & 0xff) << 16);
0615:
0616:                    if (this .traceProtocol) {
0617:                        StringBuffer traceMessageBuf = new StringBuffer();
0618:
0619:                        traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$
0620:                        traceMessageBuf.append(packetLength);
0621:                        traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$
0622:                        traceMessageBuf.append(StringUtils.dumpAsHex(
0623:                                this .packetHeaderBuf, 4));
0624:
0625:                        this .connection.getLog().logTrace(
0626:                                traceMessageBuf.toString());
0627:                    }
0628:
0629:                    byte multiPacketSeq = this .packetHeaderBuf[3];
0630:
0631:                    if (!this .packetSequenceReset) {
0632:                        if (this .enablePacketDebug && this .checkPacketSequence) {
0633:                            checkPacketSequencing(multiPacketSeq);
0634:                        }
0635:                    } else {
0636:                        this .packetSequenceReset = false;
0637:                    }
0638:
0639:                    this .readPacketSequence = multiPacketSeq;
0640:
0641:                    // Read data
0642:                    byte[] buffer = new byte[packetLength + 1];
0643:                    int numBytesRead = readFully(this .mysqlInput, buffer, 0,
0644:                            packetLength);
0645:
0646:                    if (numBytesRead != packetLength) {
0647:                        throw new IOException("Short read, expected "
0648:                                + packetLength + " bytes, only read "
0649:                                + numBytesRead);
0650:                    }
0651:
0652:                    buffer[packetLength] = 0;
0653:
0654:                    Buffer packet = new Buffer(buffer);
0655:                    packet.setBufLength(packetLength + 1);
0656:
0657:                    if (this .traceProtocol) {
0658:                        StringBuffer traceMessageBuf = new StringBuffer();
0659:
0660:                        traceMessageBuf.append(Messages.getString("MysqlIO.4")); //$NON-NLS-1$
0661:                        traceMessageBuf.append(getPacketDumpToLog(packet,
0662:                                packetLength));
0663:
0664:                        this .connection.getLog().logTrace(
0665:                                traceMessageBuf.toString());
0666:                    }
0667:
0668:                    if (this .enablePacketDebug) {
0669:                        enqueuePacketForDebugging(false, false, 0,
0670:                                this .packetHeaderBuf, packet);
0671:                    }
0672:
0673:                    return packet;
0674:                } catch (IOException ioEx) {
0675:                    throw SQLError.createCommunicationsException(
0676:                            this .connection, this .lastPacketSentTimeMs, ioEx);
0677:                } catch (OutOfMemoryError oom) {
0678:                    try {
0679:                        this .connection.realClose(false, false, true, oom);
0680:                    } finally {
0681:                        throw oom;
0682:                    }
0683:                }
0684:            }
0685:
0686:            /**
0687:             * Unpacks the Field information from the given packet. Understands pre 4.1
0688:             * and post 4.1 server version field packet structures.
0689:             *
0690:             * @param packet the packet containing the field information
0691:             * @param extractDefaultValues should default values be extracted?
0692:             *
0693:             * @return the unpacked field
0694:             *
0695:             * @throws SQLException DOCUMENT ME!
0696:             */
0697:            protected final Field unpackField(Buffer packet,
0698:                    boolean extractDefaultValues) throws SQLException {
0699:                if (this .use41Extensions) {
0700:                    // we only store the position of the string and
0701:                    // materialize only if needed...
0702:                    if (this .has41NewNewProt) {
0703:                        // Not used yet, 5.0?
0704:                        int catalogNameStart = packet.getPosition() + 1;
0705:                        int catalogNameLength = packet.fastSkipLenString();
0706:                        catalogNameStart = adjustStartForFieldLength(
0707:                                catalogNameStart, catalogNameLength);
0708:                    }
0709:
0710:                    int databaseNameStart = packet.getPosition() + 1;
0711:                    int databaseNameLength = packet.fastSkipLenString();
0712:                    databaseNameStart = adjustStartForFieldLength(
0713:                            databaseNameStart, databaseNameLength);
0714:
0715:                    int tableNameStart = packet.getPosition() + 1;
0716:                    int tableNameLength = packet.fastSkipLenString();
0717:                    tableNameStart = adjustStartForFieldLength(tableNameStart,
0718:                            tableNameLength);
0719:
0720:                    // orgTableName is never used so skip
0721:                    int originalTableNameStart = packet.getPosition() + 1;
0722:                    int originalTableNameLength = packet.fastSkipLenString();
0723:                    originalTableNameStart = adjustStartForFieldLength(
0724:                            originalTableNameStart, originalTableNameLength);
0725:
0726:                    // we only store the position again...
0727:                    int nameStart = packet.getPosition() + 1;
0728:                    int nameLength = packet.fastSkipLenString();
0729:
0730:                    nameStart = adjustStartForFieldLength(nameStart, nameLength);
0731:
0732:                    // orgColName is not required so skip...
0733:                    int originalColumnNameStart = packet.getPosition() + 1;
0734:                    int originalColumnNameLength = packet.fastSkipLenString();
0735:                    originalColumnNameStart = adjustStartForFieldLength(
0736:                            originalColumnNameStart, originalColumnNameLength);
0737:
0738:                    packet.readByte();
0739:
0740:                    short charSetNumber = (short) packet.readInt();
0741:
0742:                    long colLength = 0;
0743:
0744:                    if (this .has41NewNewProt) {
0745:                        colLength = packet.readLong();
0746:                    } else {
0747:                        colLength = packet.readLongInt();
0748:                    }
0749:
0750:                    int colType = packet.readByte() & 0xff;
0751:
0752:                    short colFlag = 0;
0753:
0754:                    if (this .hasLongColumnInfo) {
0755:                        colFlag = (short) packet.readInt();
0756:                    } else {
0757:                        colFlag = (short) (packet.readByte() & 0xff);
0758:                    }
0759:
0760:                    int colDecimals = packet.readByte() & 0xff;
0761:
0762:                    int defaultValueStart = -1;
0763:                    int defaultValueLength = -1;
0764:
0765:                    if (extractDefaultValues) {
0766:                        defaultValueStart = packet.getPosition() + 1;
0767:                        defaultValueLength = packet.fastSkipLenString();
0768:                    }
0769:
0770:                    Field field = new Field(this .connection, packet
0771:                            .getByteBuffer(), databaseNameStart,
0772:                            databaseNameLength, tableNameStart,
0773:                            tableNameLength, originalTableNameStart,
0774:                            originalTableNameLength, nameStart, nameLength,
0775:                            originalColumnNameStart, originalColumnNameLength,
0776:                            colLength, colType, colFlag, colDecimals,
0777:                            defaultValueStart, defaultValueLength,
0778:                            charSetNumber);
0779:
0780:                    return field;
0781:                }
0782:
0783:                int tableNameStart = packet.getPosition() + 1;
0784:                int tableNameLength = packet.fastSkipLenString();
0785:                tableNameStart = adjustStartForFieldLength(tableNameStart,
0786:                        tableNameLength);
0787:
0788:                int nameStart = packet.getPosition() + 1;
0789:                int nameLength = packet.fastSkipLenString();
0790:                nameStart = adjustStartForFieldLength(nameStart, nameLength);
0791:
0792:                int colLength = packet.readnBytes();
0793:                int colType = packet.readnBytes();
0794:                packet.readByte(); // We know it's currently 2
0795:
0796:                short colFlag = 0;
0797:
0798:                if (this .hasLongColumnInfo) {
0799:                    colFlag = (short) (packet.readInt());
0800:                } else {
0801:                    colFlag = (short) (packet.readByte() & 0xff);
0802:                }
0803:
0804:                int colDecimals = (packet.readByte() & 0xff);
0805:
0806:                if (this .colDecimalNeedsBump) {
0807:                    colDecimals++;
0808:                }
0809:
0810:                Field field = new Field(this .connection,
0811:                        packet.getByteBuffer(), nameStart, nameLength,
0812:                        tableNameStart, tableNameLength, colLength, colType,
0813:                        colFlag, colDecimals);
0814:
0815:                return field;
0816:            }
0817:
0818:            private int adjustStartForFieldLength(int nameStart, int nameLength) {
0819:                if (nameLength < 251) {
0820:                    return nameStart;
0821:                }
0822:
0823:                if (nameLength >= 251 && nameLength < 65536) {
0824:                    return nameStart + 2;
0825:                }
0826:
0827:                if (nameLength >= 65536 && nameLength < 16777216) {
0828:                    return nameStart + 3;
0829:                }
0830:
0831:                return nameStart + 8;
0832:            }
0833:
0834:            protected boolean isSetNeededForAutoCommitMode(
0835:                    boolean autoCommitFlag) {
0836:                if (this .use41Extensions
0837:                        && this .connection.getElideSetAutoCommits()) {
0838:                    boolean autoCommitModeOnServer = ((this .serverStatus & SERVER_STATUS_AUTOCOMMIT) != 0);
0839:
0840:                    if (!autoCommitFlag && versionMeetsMinimum(5, 0, 0)) {
0841:                        // Just to be safe, check if a transaction is in progress on the server....
0842:                        // if so, then we must be in autoCommit == false
0843:                        // therefore return the opposite of transaction status
0844:                        boolean inTransactionOnServer = ((this .serverStatus & SERVER_STATUS_IN_TRANS) != 0);
0845:
0846:                        return !inTransactionOnServer;
0847:                    }
0848:
0849:                    return autoCommitModeOnServer != autoCommitFlag;
0850:                }
0851:
0852:                return true;
0853:            }
0854:
0855:            protected boolean inTransactionOnServer() {
0856:                return (this .serverStatus & SERVER_STATUS_IN_TRANS) != 0;
0857:            }
0858:
0859:            /**
0860:             * Re-authenticates as the given user and password
0861:             *
0862:             * @param userName DOCUMENT ME!
0863:             * @param password DOCUMENT ME!
0864:             * @param database DOCUMENT ME!
0865:             *
0866:             * @throws SQLException DOCUMENT ME!
0867:             */
0868:            protected void changeUser(String userName, String password,
0869:                    String database) throws SQLException {
0870:                this .packetSequence = -1;
0871:
0872:                int passwordLength = 16;
0873:                int userLength = (userName != null) ? userName.length() : 0;
0874:                int databaseLength = (database != null) ? database.length() : 0;
0875:
0876:                int packLength = ((userLength + passwordLength + databaseLength) * 2)
0877:                        + 7 + HEADER_LENGTH + AUTH_411_OVERHEAD;
0878:
0879:                if ((this .serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
0880:                    Buffer changeUserPacket = new Buffer(packLength + 1);
0881:                    changeUserPacket
0882:                            .writeByte((byte) MysqlDefs.COM_CHANGE_USER);
0883:
0884:                    if (versionMeetsMinimum(4, 1, 1)) {
0885:                        secureAuth411(changeUserPacket, packLength, userName,
0886:                                password, database, false);
0887:                    } else {
0888:                        secureAuth(changeUserPacket, packLength, userName,
0889:                                password, database, false);
0890:                    }
0891:                } else {
0892:                    // Passwords can be 16 chars long
0893:                    Buffer packet = new Buffer(packLength);
0894:                    packet.writeByte((byte) MysqlDefs.COM_CHANGE_USER);
0895:
0896:                    // User/Password data
0897:                    packet.writeString(userName);
0898:
0899:                    if (this .protocolVersion > 9) {
0900:                        packet.writeString(Util.newCrypt(password, this .seed));
0901:                    } else {
0902:                        packet.writeString(Util.oldCrypt(password, this .seed));
0903:                    }
0904:
0905:                    boolean localUseConnectWithDb = this .useConnectWithDb
0906:                            && (database != null && database.length() > 0);
0907:
0908:                    if (localUseConnectWithDb) {
0909:                        packet.writeString(database);
0910:                    }
0911:
0912:                    send(packet, packet.getPosition());
0913:                    checkErrorPacket();
0914:
0915:                    if (!localUseConnectWithDb) {
0916:                        changeDatabaseTo(database);
0917:                    }
0918:                }
0919:            }
0920:
0921:            /**
0922:             * Checks for errors in the reply packet, and if none, returns the reply
0923:             * packet, ready for reading
0924:             *
0925:             * @return a packet ready for reading.
0926:             *
0927:             * @throws SQLException is the packet is an error packet
0928:             */
0929:            protected Buffer checkErrorPacket() throws SQLException {
0930:                return checkErrorPacket(-1);
0931:            }
0932:
0933:            /**
0934:             * Determines if the database charset is the same as the platform charset
0935:             */
0936:            protected void checkForCharsetMismatch() {
0937:                if (this .connection.getUseUnicode()
0938:                        && (this .connection.getEncoding() != null)) {
0939:                    String encodingToCheck = jvmPlatformCharset;
0940:
0941:                    if (encodingToCheck == null) {
0942:                        encodingToCheck = System.getProperty("file.encoding"); //$NON-NLS-1$
0943:                    }
0944:
0945:                    if (encodingToCheck == null) {
0946:                        this .platformDbCharsetMatches = false;
0947:                    } else {
0948:                        this .platformDbCharsetMatches = encodingToCheck
0949:                                .equals(this .connection.getEncoding());
0950:                    }
0951:                }
0952:            }
0953:
0954:            protected void clearInputStream() throws SQLException {
0955:
0956:                try {
0957:                    int len = this .mysqlInput.available();
0958:
0959:                    while (len > 0) {
0960:                        this .mysqlInput.skip(len);
0961:                        len = this .mysqlInput.available();
0962:                    }
0963:                } catch (IOException ioEx) {
0964:                    throw SQLError.createCommunicationsException(
0965:                            this .connection, this .lastPacketSentTimeMs, ioEx);
0966:                }
0967:            }
0968:
0969:            protected void resetReadPacketSequence() {
0970:                this .readPacketSequence = 0;
0971:            }
0972:
0973:            protected void dumpPacketRingBuffer() throws SQLException {
0974:                if ((this .packetDebugRingBuffer != null)
0975:                        && this .connection.getEnablePacketDebug()) {
0976:                    StringBuffer dumpBuffer = new StringBuffer();
0977:
0978:                    dumpBuffer
0979:                            .append("Last "
0980:                                    + this .packetDebugRingBuffer.size()
0981:                                    + " packets received from server, from oldest->newest:\n");
0982:                    dumpBuffer.append("\n");
0983:
0984:                    for (Iterator ringBufIter = this .packetDebugRingBuffer
0985:                            .iterator(); ringBufIter.hasNext();) {
0986:                        dumpBuffer.append((StringBuffer) ringBufIter.next());
0987:                        dumpBuffer.append("\n");
0988:                    }
0989:
0990:                    this .connection.getLog().logTrace(dumpBuffer.toString());
0991:                }
0992:            }
0993:
0994:            /**
0995:             * Runs an 'EXPLAIN' on the given query and dumps the results to  the log
0996:             *
0997:             * @param querySQL DOCUMENT ME!
0998:             * @param truncatedQuery DOCUMENT ME!
0999:             *
1000:             * @throws SQLException DOCUMENT ME!
1001:             */
1002:            protected void explainSlowQuery(byte[] querySQL,
1003:                    String truncatedQuery) throws SQLException {
1004:                if (StringUtils.startsWithIgnoreCaseAndWs(truncatedQuery,
1005:                        "SELECT")) { //$NON-NLS-1$
1006:
1007:                    PreparedStatement stmt = null;
1008:                    java.sql.ResultSet rs = null;
1009:
1010:                    try {
1011:                        stmt = this .connection
1012:                                .clientPrepareStatement("EXPLAIN ?"); //$NON-NLS-1$
1013:                        stmt.setBytesNoEscapeNoQuotes(1, querySQL);
1014:                        rs = stmt.executeQuery();
1015:
1016:                        StringBuffer explainResults = new StringBuffer(Messages
1017:                                .getString("MysqlIO.8") + truncatedQuery //$NON-NLS-1$
1018:                                + Messages.getString("MysqlIO.9")); //$NON-NLS-1$
1019:
1020:                        ResultSetUtil.appendResultSetSlashGStyle(
1021:                                explainResults, rs);
1022:
1023:                        this .connection.getLog().logWarn(
1024:                                explainResults.toString());
1025:                    } catch (SQLException sqlEx) {
1026:                    } finally {
1027:                        if (rs != null) {
1028:                            rs.close();
1029:                        }
1030:
1031:                        if (stmt != null) {
1032:                            stmt.close();
1033:                        }
1034:                    }
1035:                } else {
1036:                }
1037:            }
1038:
1039:            static int getMaxBuf() {
1040:                return maxBufferSize;
1041:            }
1042:
1043:            /**
1044:             * Get the major version of the MySQL server we are talking to.
1045:             *
1046:             * @return DOCUMENT ME!
1047:             */
1048:            final int getServerMajorVersion() {
1049:                return this .serverMajorVersion;
1050:            }
1051:
1052:            /**
1053:             * Get the minor version of the MySQL server we are talking to.
1054:             *
1055:             * @return DOCUMENT ME!
1056:             */
1057:            final int getServerMinorVersion() {
1058:                return this .serverMinorVersion;
1059:            }
1060:
1061:            /**
1062:             * Get the sub-minor version of the MySQL server we are talking to.
1063:             *
1064:             * @return DOCUMENT ME!
1065:             */
1066:            final int getServerSubMinorVersion() {
1067:                return this .serverSubMinorVersion;
1068:            }
1069:
1070:            /**
1071:             * Get the version string of the server we are talking to
1072:             *
1073:             * @return DOCUMENT ME!
1074:             */
1075:            String getServerVersion() {
1076:                return this .serverVersion;
1077:            }
1078:
1079:            /**
1080:             * Initialize communications with the MySQL server. Handles logging on, and
1081:             * handling initial connection errors.
1082:             *
1083:             * @param user DOCUMENT ME!
1084:             * @param password DOCUMENT ME!
1085:             * @param database DOCUMENT ME!
1086:             *
1087:             * @throws SQLException DOCUMENT ME!
1088:             * @throws CommunicationsException DOCUMENT ME!
1089:             */
1090:            void doHandshake(String user, String password, String database)
1091:                    throws SQLException {
1092:                // Read the first packet
1093:                this .checkPacketSequence = false;
1094:                this .readPacketSequence = 0;
1095:
1096:                Buffer buf = readPacket();
1097:
1098:                // Get the protocol version
1099:                this .protocolVersion = buf.readByte();
1100:
1101:                if (this .protocolVersion == -1) {
1102:                    try {
1103:                        this .mysqlConnection.close();
1104:                    } catch (Exception e) {
1105:                        // ignore
1106:                    }
1107:
1108:                    int errno = 2000;
1109:
1110:                    errno = buf.readInt();
1111:
1112:                    String serverErrorMessage = buf.readString();
1113:
1114:                    StringBuffer errorBuf = new StringBuffer(Messages
1115:                            .getString("MysqlIO.10")); //$NON-NLS-1$
1116:                    errorBuf.append(serverErrorMessage);
1117:                    errorBuf.append("\""); //$NON-NLS-1$
1118:
1119:                    String xOpen = SQLError.mysqlToSqlState(errno,
1120:                            this .connection.getUseSqlStateCodes());
1121:
1122:                    throw SQLError.createSQLException(SQLError.get(xOpen)
1123:                            + ", " //$NON-NLS-1$
1124:                            + errorBuf.toString(), xOpen, errno);
1125:                }
1126:
1127:                this .serverVersion = buf.readString();
1128:
1129:                // Parse the server version into major/minor/subminor
1130:                int point = this .serverVersion.indexOf('.'); //$NON-NLS-1$
1131:
1132:                if (point != -1) {
1133:                    try {
1134:                        int n = Integer.parseInt(this .serverVersion.substring(
1135:                                0, point));
1136:                        this .serverMajorVersion = n;
1137:                    } catch (NumberFormatException NFE1) {
1138:                        // ignore
1139:                    }
1140:
1141:                    String remaining = this .serverVersion.substring(point + 1,
1142:                            this .serverVersion.length());
1143:                    point = remaining.indexOf('.'); //$NON-NLS-1$
1144:
1145:                    if (point != -1) {
1146:                        try {
1147:                            int n = Integer.parseInt(remaining.substring(0,
1148:                                    point));
1149:                            this .serverMinorVersion = n;
1150:                        } catch (NumberFormatException nfe) {
1151:                            // ignore
1152:                        }
1153:
1154:                        remaining = remaining.substring(point + 1, remaining
1155:                                .length());
1156:
1157:                        int pos = 0;
1158:
1159:                        while (pos < remaining.length()) {
1160:                            if ((remaining.charAt(pos) < '0')
1161:                                    || (remaining.charAt(pos) > '9')) {
1162:                                break;
1163:                            }
1164:
1165:                            pos++;
1166:                        }
1167:
1168:                        try {
1169:                            int n = Integer.parseInt(remaining
1170:                                    .substring(0, pos));
1171:                            this .serverSubMinorVersion = n;
1172:                        } catch (NumberFormatException nfe) {
1173:                            // ignore
1174:                        }
1175:                    }
1176:                }
1177:
1178:                if (versionMeetsMinimum(4, 0, 8)) {
1179:                    this .maxThreeBytes = (256 * 256 * 256) - 1;
1180:                    this .useNewLargePackets = true;
1181:                } else {
1182:                    this .maxThreeBytes = 255 * 255 * 255;
1183:                    this .useNewLargePackets = false;
1184:                }
1185:
1186:                this .colDecimalNeedsBump = versionMeetsMinimum(3, 23, 0);
1187:                this .colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15); // guess? Not noted in changelog
1188:                this .useNewUpdateCounts = versionMeetsMinimum(3, 22, 5);
1189:
1190:                threadId = buf.readLong();
1191:                this .seed = buf.readString();
1192:
1193:                this .serverCapabilities = 0;
1194:
1195:                if (buf.getPosition() < buf.getBufLength()) {
1196:                    this .serverCapabilities = buf.readInt();
1197:                }
1198:
1199:                if (versionMeetsMinimum(4, 1, 1)) {
1200:                    int position = buf.getPosition();
1201:
1202:                    /* New protocol with 16 bytes to describe server characteristics */
1203:                    this .serverCharsetIndex = buf.readByte() & 0xff;
1204:                    this .serverStatus = buf.readInt();
1205:                    buf.setPosition(position + 16);
1206:
1207:                    String seedPart2 = buf.readString();
1208:                    StringBuffer newSeed = new StringBuffer(20);
1209:                    newSeed.append(this .seed);
1210:                    newSeed.append(seedPart2);
1211:                    this .seed = newSeed.toString();
1212:                }
1213:
1214:                if (((this .serverCapabilities & CLIENT_COMPRESS) != 0)
1215:                        && this .connection.getUseCompression()) {
1216:                    this .clientParam |= CLIENT_COMPRESS;
1217:                }
1218:
1219:                this .useConnectWithDb = (database != null)
1220:                        && (database.length() > 0)
1221:                        && !this .connection.getCreateDatabaseIfNotExist();
1222:
1223:                if (this .useConnectWithDb) {
1224:                    this .clientParam |= CLIENT_CONNECT_WITH_DB;
1225:                }
1226:
1227:                if (((this .serverCapabilities & CLIENT_SSL) == 0)
1228:                        && this .connection.getUseSSL()) {
1229:                    if (this .connection.getRequireSSL()) {
1230:                        this .connection.close();
1231:                        forceClose();
1232:                        throw SQLError
1233:                                .createSQLException(
1234:                                        Messages.getString("MysqlIO.15"), //$NON-NLS-1$
1235:                                        SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
1236:                    }
1237:
1238:                    this .connection.setUseSSL(false);
1239:                }
1240:
1241:                if ((this .serverCapabilities & CLIENT_LONG_FLAG) != 0) {
1242:                    // We understand other column flags, as well
1243:                    this .clientParam |= CLIENT_LONG_FLAG;
1244:                    this .hasLongColumnInfo = true;
1245:                }
1246:
1247:                // return FOUND rows
1248:                this .clientParam |= CLIENT_FOUND_ROWS;
1249:
1250:                if (this .connection.getAllowLoadLocalInfile()) {
1251:                    this .clientParam |= CLIENT_LOCAL_FILES;
1252:                }
1253:
1254:                if (this .isInteractiveClient) {
1255:                    this .clientParam |= CLIENT_INTERACTIVE;
1256:                }
1257:
1258:                // Authenticate
1259:                if (this .protocolVersion > 9) {
1260:                    this .clientParam |= CLIENT_LONG_PASSWORD; // for long passwords
1261:                } else {
1262:                    this .clientParam &= ~CLIENT_LONG_PASSWORD;
1263:                }
1264:
1265:                //
1266:                // 4.1 has some differences in the protocol
1267:                //
1268:                if (versionMeetsMinimum(4, 1, 0)) {
1269:                    if (versionMeetsMinimum(4, 1, 1)) {
1270:                        this .clientParam |= CLIENT_PROTOCOL_41;
1271:                        this .has41NewNewProt = true;
1272:
1273:                        // Need this to get server status values
1274:                        this .clientParam |= CLIENT_TRANSACTIONS;
1275:
1276:                        // We always allow multiple result sets
1277:                        this .clientParam |= CLIENT_MULTI_RESULTS;
1278:
1279:                        // We allow the user to configure whether
1280:                        // or not they want to support multiple queries
1281:                        // (by default, this is disabled).
1282:                        if (this .connection.getAllowMultiQueries()) {
1283:                            this .clientParam |= CLIENT_MULTI_QUERIES;
1284:                        }
1285:                    } else {
1286:                        this .clientParam |= CLIENT_RESERVED;
1287:                        this .has41NewNewProt = false;
1288:                    }
1289:
1290:                    this .use41Extensions = true;
1291:                }
1292:
1293:                int passwordLength = 16;
1294:                int userLength = (user != null) ? user.length() : 0;
1295:                int databaseLength = (database != null) ? database.length() : 0;
1296:
1297:                int packLength = ((userLength + passwordLength + databaseLength) * 2)
1298:                        + 7 + HEADER_LENGTH + AUTH_411_OVERHEAD;
1299:
1300:                Buffer packet = null;
1301:
1302:                if (!this .connection.getUseSSL()) {
1303:                    if ((this .serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
1304:                        this .clientParam |= CLIENT_SECURE_CONNECTION;
1305:
1306:                        if (versionMeetsMinimum(4, 1, 1)) {
1307:                            secureAuth411(null, packLength, user, password,
1308:                                    database, true);
1309:                        } else {
1310:                            secureAuth(null, packLength, user, password,
1311:                                    database, true);
1312:                        }
1313:                    } else {
1314:                        // Passwords can be 16 chars long
1315:                        packet = new Buffer(packLength);
1316:
1317:                        if ((this .clientParam & CLIENT_RESERVED) != 0) {
1318:                            if (versionMeetsMinimum(4, 1, 1)) {
1319:                                packet.writeLong(this .clientParam);
1320:                                packet.writeLong(this .maxThreeBytes);
1321:
1322:                                // charset, JDBC will connect as 'latin1',
1323:                                // and use 'SET NAMES' to change to the desired
1324:                                // charset after the connection is established.
1325:                                packet.writeByte((byte) 8);
1326:
1327:                                // Set of bytes reserved for future use.
1328:                                packet.writeBytesNoNull(new byte[23]);
1329:                            } else {
1330:                                packet.writeLong(this .clientParam);
1331:                                packet.writeLong(this .maxThreeBytes);
1332:                            }
1333:                        } else {
1334:                            packet.writeInt((int) this .clientParam);
1335:                            packet.writeLongInt(this .maxThreeBytes);
1336:                        }
1337:
1338:                        // User/Password data
1339:                        packet.writeString(user, CODE_PAGE_1252,
1340:                                this .connection);
1341:
1342:                        if (this .protocolVersion > 9) {
1343:                            packet
1344:                                    .writeString(Util.newCrypt(password,
1345:                                            this .seed), CODE_PAGE_1252,
1346:                                            this .connection);
1347:                        } else {
1348:                            packet
1349:                                    .writeString(Util.oldCrypt(password,
1350:                                            this .seed), CODE_PAGE_1252,
1351:                                            this .connection);
1352:                        }
1353:
1354:                        if (this .useConnectWithDb) {
1355:                            packet.writeString(database, CODE_PAGE_1252,
1356:                                    this .connection);
1357:                        }
1358:
1359:                        send(packet, packet.getPosition());
1360:                    }
1361:                } else {
1362:                    negotiateSSLConnection(user, password, database, packLength);
1363:                }
1364:
1365:                // Check for errors, not for 4.1.1 or newer,
1366:                // as the new auth protocol doesn't work that way
1367:                // (see secureAuth411() for more details...)
1368:                if (!versionMeetsMinimum(4, 1, 1)) {
1369:                    checkErrorPacket();
1370:                }
1371:
1372:                //
1373:                // Can't enable compression until after handshake
1374:                //
1375:                if (((this .serverCapabilities & CLIENT_COMPRESS) != 0)
1376:                        && this .connection.getUseCompression()) {
1377:                    // The following matches with ZLIB's
1378:                    // compress()
1379:                    this .deflater = new Deflater();
1380:                    this .useCompression = true;
1381:                    this .mysqlInput = new CompressedInputStream(
1382:                            this .connection, this .mysqlInput);
1383:                }
1384:
1385:                if (!this .useConnectWithDb) {
1386:                    changeDatabaseTo(database);
1387:                }
1388:            }
1389:
1390:            private void changeDatabaseTo(String database) throws SQLException {
1391:                if (database == null || database.length() == 0) {
1392:                    return;
1393:                }
1394:
1395:                try {
1396:                    sendCommand(MysqlDefs.INIT_DB, database, null, false, null);
1397:                } catch (Exception ex) {
1398:                    if (this .connection.getCreateDatabaseIfNotExist()) {
1399:                        sendCommand(MysqlDefs.QUERY,
1400:                                "CREATE DATABASE IF NOT EXISTS " + database,
1401:                                null, false, null);
1402:                        sendCommand(MysqlDefs.INIT_DB, database, null, false,
1403:                                null);
1404:                    } else {
1405:                        throw SQLError.createCommunicationsException(
1406:                                this .connection, this .lastPacketSentTimeMs, ex);
1407:                    }
1408:                }
1409:            }
1410:
1411:            /**
1412:             * Retrieve one row from the MySQL server. Note: this method is not
1413:             * thread-safe, but it is only called from methods that are guarded by
1414:             * synchronizing on this object.
1415:             *
1416:             * @param fields DOCUMENT ME!
1417:             * @param columnCount DOCUMENT ME!
1418:             * @param isBinaryEncoded DOCUMENT ME!
1419:             * @param resultSetConcurrency DOCUMENT ME!
1420:             * @param b
1421:             *
1422:             * @return DOCUMENT ME!
1423:             *
1424:             * @throws SQLException DOCUMENT ME!
1425:             */
1426:            final ResultSetRow nextRow(Field[] fields, int columnCount,
1427:                    boolean isBinaryEncoded, int resultSetConcurrency,
1428:                    boolean useBufferRowIfPossible,
1429:                    boolean useBufferRowExplicit,
1430:                    boolean canReuseRowPacketForBufferRow,
1431:                    Buffer existingRowPacket) throws SQLException {
1432:
1433:                if (this .useDirectRowUnpack && existingRowPacket == null
1434:                        && !isBinaryEncoded && !useBufferRowIfPossible
1435:                        && !useBufferRowExplicit) {
1436:                    return nextRowFast(fields, columnCount, isBinaryEncoded,
1437:                            resultSetConcurrency, useBufferRowIfPossible,
1438:                            useBufferRowExplicit, canReuseRowPacketForBufferRow);
1439:                }
1440:
1441:                Buffer rowPacket = null;
1442:
1443:                if (existingRowPacket == null) {
1444:                    rowPacket = checkErrorPacket();
1445:
1446:                    if (!useBufferRowExplicit && useBufferRowIfPossible) {
1447:                        if (rowPacket.getBufLength() > this .useBufferRowSizeThreshold) {
1448:                            useBufferRowExplicit = true;
1449:                        }
1450:                    }
1451:                } else {
1452:                    // We attempted to do nextRowFast(), but the packet was a
1453:                    // multipacket, so we couldn't unpack it directly
1454:                    rowPacket = existingRowPacket;
1455:                    checkErrorPacket(existingRowPacket);
1456:                }
1457:
1458:                if (!isBinaryEncoded) {
1459:                    //
1460:                    // Didn't read an error, so re-position to beginning
1461:                    // of packet in order to read result set data
1462:                    //
1463:                    rowPacket.setPosition(rowPacket.getPosition() - 1);
1464:
1465:                    if (!rowPacket.isLastDataPacket()) {
1466:                        if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE
1467:                                || (!useBufferRowIfPossible && !useBufferRowExplicit)) {
1468:
1469:                            byte[][] rowData = new byte[columnCount][];
1470:
1471:                            for (int i = 0; i < columnCount; i++) {
1472:                                rowData[i] = rowPacket.readLenByteArray(0);
1473:                            }
1474:
1475:                            return new ByteArrayRow(rowData);
1476:                        }
1477:
1478:                        if (!canReuseRowPacketForBufferRow) {
1479:                            this .reusablePacket = new Buffer(rowPacket
1480:                                    .getBufLength());
1481:                        }
1482:
1483:                        return new BufferRow(rowPacket, fields, false);
1484:
1485:                    }
1486:
1487:                    readServerStatusForResultSets(rowPacket);
1488:
1489:                    return null;
1490:                }
1491:
1492:                //
1493:                // Handle binary-encoded data for server-side
1494:                // PreparedStatements...
1495:                //
1496:                if (!rowPacket.isLastDataPacket()) {
1497:                    if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE
1498:                            || (!useBufferRowIfPossible && !useBufferRowExplicit)) {
1499:                        return unpackBinaryResultSetRow(fields, rowPacket,
1500:                                resultSetConcurrency);
1501:                    }
1502:
1503:                    if (!canReuseRowPacketForBufferRow) {
1504:                        this .reusablePacket = new Buffer(rowPacket
1505:                                .getBufLength());
1506:                    }
1507:
1508:                    return new BufferRow(rowPacket, fields, true);
1509:                }
1510:
1511:                rowPacket.setPosition(rowPacket.getPosition() - 1);
1512:                readServerStatusForResultSets(rowPacket);
1513:
1514:                return null;
1515:            }
1516:
1517:            final ResultSetRow nextRowFast(Field[] fields, int columnCount,
1518:                    boolean isBinaryEncoded, int resultSetConcurrency,
1519:                    boolean useBufferRowIfPossible,
1520:                    boolean useBufferRowExplicit, boolean canReuseRowPacket)
1521:                    throws SQLException {
1522:                try {
1523:                    int lengthRead = readFully(this .mysqlInput,
1524:                            this .packetHeaderBuf, 0, 4);
1525:
1526:                    if (lengthRead < 4) {
1527:                        forceClose();
1528:                        throw new RuntimeException(Messages
1529:                                .getString("MysqlIO.43")); //$NON-NLS-1$
1530:                    }
1531:
1532:                    int packetLength = (this .packetHeaderBuf[0] & 0xff)
1533:                            + ((this .packetHeaderBuf[1] & 0xff) << 8)
1534:                            + ((this .packetHeaderBuf[2] & 0xff) << 16);
1535:
1536:                    // Have we stumbled upon a multi-packet?
1537:                    if (packetLength == this .maxThreeBytes) {
1538:                        reuseAndReadPacket(this .reusablePacket, packetLength);
1539:
1540:                        // Go back to "old" way which uses packets
1541:                        return nextRow(fields, columnCount, isBinaryEncoded,
1542:                                resultSetConcurrency, useBufferRowIfPossible,
1543:                                useBufferRowExplicit, canReuseRowPacket,
1544:                                this .reusablePacket);
1545:                    }
1546:
1547:                    // Does this go over the threshold where we should use a BufferRow?
1548:
1549:                    if (packetLength > this .useBufferRowSizeThreshold) {
1550:                        reuseAndReadPacket(this .reusablePacket, packetLength);
1551:
1552:                        // Go back to "old" way which uses packets
1553:                        return nextRow(fields, columnCount, isBinaryEncoded,
1554:                                resultSetConcurrency, true, true, false,
1555:                                this .reusablePacket);
1556:                    }
1557:
1558:                    int remaining = packetLength;
1559:
1560:                    boolean firstTime = true;
1561:
1562:                    byte[][] rowData = null;
1563:
1564:                    for (int i = 0; i < columnCount; i++) {
1565:
1566:                        int sw = this .mysqlInput.read() & 0xff;
1567:                        remaining--;
1568:
1569:                        if (firstTime) {
1570:                            if (sw == 255) {
1571:                                // error packet
1572:                                Buffer errorPacket = new Buffer(packetLength);
1573:                                errorPacket.writeByte((byte) sw);
1574:                                readFully(this .mysqlInput, errorPacket
1575:                                        .getByteBuffer(), 1, packetLength - 1);
1576:
1577:                                checkErrorPacket(errorPacket);
1578:                            }
1579:
1580:                            if (sw == 254 && packetLength < 9) {
1581:                                this .warningCount = (this .mysqlInput.read() & 0xff)
1582:                                        | ((this .mysqlInput.read() & 0xff) << 8);
1583:                                remaining -= 2;
1584:
1585:                                if (this .warningCount > 0) {
1586:                                    this .hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
1587:                                }
1588:
1589:                                this .serverStatus = (this .mysqlInput.read() & 0xff)
1590:                                        | ((this .mysqlInput.read() & 0xff) << 8);
1591:                                remaining -= 2;
1592:
1593:                                if (remaining > 0) {
1594:                                    skipFully(this .mysqlInput, remaining);
1595:                                }
1596:
1597:                                return null; // last data packet
1598:                            }
1599:
1600:                            rowData = new byte[columnCount][];
1601:
1602:                            firstTime = false;
1603:                        }
1604:
1605:                        int len = 0;
1606:
1607:                        switch (sw) {
1608:                        case 251:
1609:                            len = NULL_LENGTH;
1610:                            break;
1611:
1612:                        case 252:
1613:                            len = (this .mysqlInput.read() & 0xff)
1614:                                    | ((this .mysqlInput.read() & 0xff) << 8);
1615:                            remaining -= 2;
1616:                            break;
1617:
1618:                        case 253:
1619:                            len = (this .mysqlInput.read() & 0xff)
1620:                                    | ((this .mysqlInput.read() & 0xff) << 8)
1621:                                    | ((this .mysqlInput.read() & 0xff) << 16);
1622:
1623:                            remaining -= 3;
1624:                            break;
1625:
1626:                        case 254:
1627:                            len = (int) ((this .mysqlInput.read() & 0xff)
1628:                                    | ((long) (this .mysqlInput.read() & 0xff) << 8)
1629:                                    | ((long) (this .mysqlInput.read() & 0xff) << 16)
1630:                                    | ((long) (this .mysqlInput.read() & 0xff) << 24)
1631:                                    | ((long) (this .mysqlInput.read() & 0xff) << 32)
1632:                                    | ((long) (this .mysqlInput.read() & 0xff) << 40)
1633:                                    | ((long) (this .mysqlInput.read() & 0xff) << 48) | ((long) (this .mysqlInput
1634:                                    .read() & 0xff) << 56));
1635:                            remaining -= 8;
1636:                            break;
1637:
1638:                        default:
1639:                            len = sw;
1640:                        }
1641:
1642:                        if (len == NULL_LENGTH) {
1643:                            rowData[i] = null;
1644:                        } else if (len == 0) {
1645:                            rowData[i] = Constants.EMPTY_BYTE_ARRAY;
1646:                        } else {
1647:                            rowData[i] = new byte[len];
1648:
1649:                            int bytesRead = readFully(this .mysqlInput,
1650:                                    rowData[i], 0, len);
1651:
1652:                            if (bytesRead != len) {
1653:                                throw SQLError.createCommunicationsException(
1654:                                        this .connection,
1655:                                        this .lastPacketSentTimeMs,
1656:                                        new IOException(Messages
1657:                                                .getString("MysqlIO.43")));
1658:                            }
1659:
1660:                            remaining -= bytesRead;
1661:                        }
1662:                    }
1663:
1664:                    if (remaining > 0) {
1665:                        skipFully(this .mysqlInput, remaining);
1666:                    }
1667:
1668:                    return new ByteArrayRow(rowData);
1669:                } catch (IOException ioEx) {
1670:                    throw SQLError.createCommunicationsException(
1671:                            this .connection, this .lastPacketSentTimeMs, ioEx);
1672:                }
1673:            }
1674:
1675:            /**
1676:             * Log-off of the MySQL server and close the socket.
1677:             *
1678:             * @throws SQLException DOCUMENT ME!
1679:             */
1680:            final void quit() throws SQLException {
1681:                Buffer packet = new Buffer(6);
1682:                this .packetSequence = -1;
1683:                packet.writeByte((byte) MysqlDefs.QUIT);
1684:                send(packet, packet.getPosition());
1685:                forceClose();
1686:            }
1687:
1688:            /**
1689:             * Returns the packet used for sending data (used by PreparedStatement)
1690:             * Guarded by external synchronization on a mutex.
1691:             *
1692:             * @return A packet to send data with
1693:             */
1694:            Buffer getSharedSendPacket() {
1695:                if (this .sharedSendPacket == null) {
1696:                    this .sharedSendPacket = new Buffer(INITIAL_PACKET_SIZE);
1697:                }
1698:
1699:                return this .sharedSendPacket;
1700:            }
1701:
1702:            void closeStreamer(RowData streamer) throws SQLException {
1703:                if (this .streamingData == null) {
1704:                    throw SQLError.createSQLException(Messages
1705:                            .getString("MysqlIO.17") //$NON-NLS-1$
1706:                            + streamer + Messages.getString("MysqlIO.18")); //$NON-NLS-1$
1707:                }
1708:
1709:                if (streamer != this .streamingData) {
1710:                    throw SQLError.createSQLException(Messages
1711:                            .getString("MysqlIO.19") //$NON-NLS-1$
1712:                            + streamer + Messages.getString("MysqlIO.20") //$NON-NLS-1$
1713:                            + Messages.getString("MysqlIO.21") //$NON-NLS-1$
1714:                            + Messages.getString("MysqlIO.22")); //$NON-NLS-1$
1715:                }
1716:
1717:                this .streamingData = null;
1718:            }
1719:
1720:            ResultSetImpl readAllResults(StatementImpl callingStatement,
1721:                    int maxRows, int resultSetType, int resultSetConcurrency,
1722:                    boolean streamResults, String catalog, Buffer resultPacket,
1723:                    boolean isBinaryEncoded, long preSentColumnCount,
1724:                    Field[] metadataFromCache) throws SQLException {
1725:                resultPacket.setPosition(resultPacket.getPosition() - 1);
1726:
1727:                ResultSetImpl topLevelResultSet = readResultsForQueryOrUpdate(
1728:                        callingStatement, maxRows, resultSetType,
1729:                        resultSetConcurrency, streamResults, catalog,
1730:                        resultPacket, isBinaryEncoded, preSentColumnCount,
1731:                        metadataFromCache);
1732:
1733:                ResultSetImpl currentResultSet = topLevelResultSet;
1734:
1735:                boolean checkForMoreResults = ((this .clientParam & CLIENT_MULTI_RESULTS) != 0);
1736:
1737:                boolean serverHasMoreResults = (this .serverStatus & SERVER_MORE_RESULTS_EXISTS) != 0;
1738:
1739:                //
1740:                // TODO: We need to support streaming of multiple result sets
1741:                //
1742:                if (serverHasMoreResults && streamResults) {
1743:                    clearInputStream();
1744:
1745:                    throw SQLError.createSQLException(Messages
1746:                            .getString("MysqlIO.23"), //$NON-NLS-1$
1747:                            SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
1748:                }
1749:
1750:                boolean moreRowSetsExist = checkForMoreResults
1751:                        & serverHasMoreResults;
1752:
1753:                while (moreRowSetsExist) {
1754:                    Buffer fieldPacket = checkErrorPacket();
1755:                    fieldPacket.setPosition(0);
1756:
1757:                    ResultSetImpl newResultSet = readResultsForQueryOrUpdate(
1758:                            callingStatement, maxRows, resultSetType,
1759:                            resultSetConcurrency, streamResults, catalog,
1760:                            fieldPacket, isBinaryEncoded, preSentColumnCount,
1761:                            metadataFromCache);
1762:
1763:                    currentResultSet.setNextResultSet(newResultSet);
1764:
1765:                    currentResultSet = newResultSet;
1766:
1767:                    moreRowSetsExist = (this .serverStatus & SERVER_MORE_RESULTS_EXISTS) != 0;
1768:                }
1769:
1770:                if (!streamResults) {
1771:                    clearInputStream();
1772:                }
1773:
1774:                reclaimLargeReusablePacket();
1775:
1776:                return topLevelResultSet;
1777:            }
1778:
1779:            /**
1780:             * Sets the buffer size to max-buf
1781:             */
1782:            void resetMaxBuf() {
1783:                this .maxAllowedPacket = this .connection.getMaxAllowedPacket();
1784:            }
1785:
1786:            /**
1787:             * Send a command to the MySQL server If data is to be sent with command,
1788:             * it should be put in extraData.
1789:             *
1790:             * Raw packets can be sent by setting queryPacket to something other
1791:             * than null.
1792:             *
1793:             * @param command the MySQL protocol 'command' from MysqlDefs
1794:             * @param extraData any 'string' data for the command
1795:             * @param queryPacket a packet pre-loaded with data for the protocol (i.e.
1796:             * from a client-side prepared statement).
1797:             * @param skipCheck do not call checkErrorPacket() if true
1798:             * @param extraDataCharEncoding the character encoding of the extraData
1799:             * parameter.
1800:             *
1801:             * @return the response packet from the server
1802:             *
1803:             * @throws SQLException if an I/O error or SQL error occurs
1804:             */
1805:
1806:            final Buffer sendCommand(int command, String extraData,
1807:                    Buffer queryPacket, boolean skipCheck,
1808:                    String extraDataCharEncoding) throws SQLException {
1809:                //
1810:                // We cache these locally, per-command, as the checks
1811:                // for them are in very 'hot' sections of the I/O code
1812:                // and we save 10-15% in overall performance by doing this...
1813:                //
1814:                this .enablePacketDebug = this .connection.getEnablePacketDebug();
1815:                this .traceProtocol = this .connection.getTraceProtocol();
1816:                this .readPacketSequence = 0;
1817:
1818:                try {
1819:
1820:                    checkForOutstandingStreamingData();
1821:
1822:                    // Clear serverStatus...this value is guarded by an
1823:                    // external mutex, as you can only ever be processing
1824:                    // one command at a time
1825:                    this .serverStatus = 0;
1826:                    this .hadWarnings = false;
1827:                    this .warningCount = 0;
1828:
1829:                    this .queryNoIndexUsed = false;
1830:                    this .queryBadIndexUsed = false;
1831:
1832:                    //
1833:                    // Compressed input stream needs cleared at beginning
1834:                    // of each command execution...
1835:                    //
1836:                    if (this .useCompression) {
1837:                        int bytesLeft = this .mysqlInput.available();
1838:
1839:                        if (bytesLeft > 0) {
1840:                            this .mysqlInput.skip(bytesLeft);
1841:                        }
1842:                    }
1843:
1844:                    try {
1845:                        clearInputStream();
1846:
1847:                        //
1848:                        // PreparedStatements construct their own packets,
1849:                        // for efficiency's sake.
1850:                        //
1851:                        // If this is a generic query, we need to re-use
1852:                        // the sending packet.
1853:                        //
1854:                        if (queryPacket == null) {
1855:                            int packLength = HEADER_LENGTH
1856:                                    + COMP_HEADER_LENGTH
1857:                                    + 1
1858:                                    + ((extraData != null) ? extraData.length()
1859:                                            : 0) + 2;
1860:
1861:                            if (this .sendPacket == null) {
1862:                                this .sendPacket = new Buffer(packLength);
1863:                            }
1864:
1865:                            this .packetSequence = -1;
1866:                            this .readPacketSequence = 0;
1867:                            this .checkPacketSequence = true;
1868:                            this .sendPacket.clear();
1869:
1870:                            this .sendPacket.writeByte((byte) command);
1871:
1872:                            if ((command == MysqlDefs.INIT_DB)
1873:                                    || (command == MysqlDefs.CREATE_DB)
1874:                                    || (command == MysqlDefs.DROP_DB)
1875:                                    || (command == MysqlDefs.QUERY)
1876:                                    || (command == MysqlDefs.COM_PREPARE)) {
1877:                                if (extraDataCharEncoding == null) {
1878:                                    this .sendPacket
1879:                                            .writeStringNoNull(extraData);
1880:                                } else {
1881:                                    this .sendPacket
1882:                                            .writeStringNoNull(
1883:                                                    extraData,
1884:                                                    extraDataCharEncoding,
1885:                                                    this .connection
1886:                                                            .getServerCharacterEncoding(),
1887:                                                    this .connection
1888:                                                            .parserKnowsUnicode(),
1889:                                                    this .connection);
1890:                                }
1891:                            } else if (command == MysqlDefs.PROCESS_KILL) {
1892:                                long id = Long.parseLong(extraData);
1893:                                this .sendPacket.writeLong(id);
1894:                            }
1895:
1896:                            send(this .sendPacket, this .sendPacket.getPosition());
1897:                        } else {
1898:                            this .packetSequence = -1;
1899:                            send(queryPacket, queryPacket.getPosition()); // packet passed by PreparedStatement
1900:                        }
1901:                    } catch (SQLException sqlEx) {
1902:                        // don't wrap SQLExceptions
1903:                        throw sqlEx;
1904:                    } catch (Exception ex) {
1905:                        throw SQLError.createCommunicationsException(
1906:                                this .connection, this .lastPacketSentTimeMs, ex);
1907:                    }
1908:
1909:                    Buffer returnPacket = null;
1910:
1911:                    if (!skipCheck) {
1912:                        if ((command == MysqlDefs.COM_EXECUTE)
1913:                                || (command == MysqlDefs.COM_RESET_STMT)) {
1914:                            this .readPacketSequence = 0;
1915:                            this .packetSequenceReset = true;
1916:                        }
1917:
1918:                        returnPacket = checkErrorPacket(command);
1919:                    }
1920:
1921:                    return returnPacket;
1922:                } catch (IOException ioEx) {
1923:                    throw SQLError.createCommunicationsException(
1924:                            this .connection, this .lastPacketSentTimeMs, ioEx);
1925:                }
1926:            }
1927:
1928:            private int statementExecutionDepth = 0;
1929:
1930:            /**
1931:             * Send a query stored in a packet directly to the server.
1932:             *
1933:             * @param callingStatement DOCUMENT ME!
1934:             * @param resultSetConcurrency DOCUMENT ME!
1935:             * @param characterEncoding DOCUMENT ME!
1936:             * @param queryPacket DOCUMENT ME!
1937:             * @param maxRows DOCUMENT ME!
1938:             * @param conn DOCUMENT ME!
1939:             * @param resultSetType DOCUMENT ME!
1940:             * @param resultSetConcurrency DOCUMENT ME!
1941:             * @param streamResults DOCUMENT ME!
1942:             * @param catalog DOCUMENT ME!
1943:             * @param unpackFieldInfo should we read MYSQL_FIELD info (if available)?
1944:             *
1945:             * @return DOCUMENT ME!
1946:             *
1947:             * @throws Exception DOCUMENT ME!
1948:             */
1949:            final ResultSetInternalMethods sqlQueryDirect(
1950:                    StatementImpl callingStatement, String query,
1951:                    String characterEncoding, Buffer queryPacket, int maxRows,
1952:                    int resultSetType, int resultSetConcurrency,
1953:                    boolean streamResults, String catalog,
1954:                    Field[] cachedMetadata) throws Exception {
1955:                this .statementExecutionDepth++;
1956:
1957:                try {
1958:                    if (this .statementInterceptors != null) {
1959:                        ResultSetInternalMethods interceptedResults = invokeStatementInterceptorsPre(
1960:                                query, callingStatement);
1961:
1962:                        if (interceptedResults != null) {
1963:                            return interceptedResults;
1964:                        }
1965:                    }
1966:
1967:                    long queryStartTime = 0;
1968:                    long queryEndTime = 0;
1969:
1970:                    if (query != null) {
1971:
1972:                        // We don't know exactly how many bytes we're going to get
1973:                        // from the query. Since we're dealing with Unicode, the
1974:                        // max is 2, so pad it (2 * query) + space for headers
1975:                        int packLength = HEADER_LENGTH + 1
1976:                                + (query.length() * 2) + 2;
1977:
1978:                        String statementComment = this .connection
1979:                                .getStatementComment();
1980:
1981:                        byte[] commentAsBytes = null;
1982:
1983:                        if (statementComment != null) {
1984:                            commentAsBytes = StringUtils.getBytes(
1985:                                    statementComment, null, characterEncoding,
1986:                                    this .connection
1987:                                            .getServerCharacterEncoding(),
1988:                                    this .connection.parserKnowsUnicode());
1989:
1990:                            packLength += commentAsBytes.length;
1991:                            packLength += 6; // for /*[space] [space]*/
1992:                        }
1993:
1994:                        if (this .sendPacket == null) {
1995:                            this .sendPacket = new Buffer(packLength);
1996:                        } else {
1997:                            this .sendPacket.clear();
1998:                        }
1999:
2000:                        this .sendPacket.writeByte((byte) MysqlDefs.QUERY);
2001:
2002:                        if (commentAsBytes != null) {
2003:                            this .sendPacket
2004:                                    .writeBytesNoNull(Constants.SLASH_STAR_SPACE_AS_BYTES);
2005:                            this .sendPacket.writeBytesNoNull(commentAsBytes);
2006:                            this .sendPacket
2007:                                    .writeBytesNoNull(Constants.SPACE_STAR_SLASH_SPACE_AS_BYTES);
2008:                        }
2009:
2010:                        if (characterEncoding != null) {
2011:                            if (this .platformDbCharsetMatches) {
2012:                                this .sendPacket.writeStringNoNull(query,
2013:                                        characterEncoding, this .connection
2014:                                                .getServerCharacterEncoding(),
2015:                                        this .connection.parserKnowsUnicode(),
2016:                                        this .connection);
2017:                            } else {
2018:                                if (StringUtils.startsWithIgnoreCaseAndWs(
2019:                                        query, "LOAD DATA")) { //$NON-NLS-1$
2020:                                    this .sendPacket.writeBytesNoNull(query
2021:                                            .getBytes());
2022:                                } else {
2023:                                    this .sendPacket
2024:                                            .writeStringNoNull(
2025:                                                    query,
2026:                                                    characterEncoding,
2027:                                                    this .connection
2028:                                                            .getServerCharacterEncoding(),
2029:                                                    this .connection
2030:                                                            .parserKnowsUnicode(),
2031:                                                    this .connection);
2032:                                }
2033:                            }
2034:                        } else {
2035:                            this .sendPacket.writeStringNoNull(query);
2036:                        }
2037:
2038:                        queryPacket = this .sendPacket;
2039:                    }
2040:
2041:                    byte[] queryBuf = null;
2042:                    int oldPacketPosition = 0;
2043:
2044:                    if (needToGrabQueryFromPacket) {
2045:                        queryBuf = queryPacket.getByteBuffer();
2046:
2047:                        // save the packet position
2048:                        oldPacketPosition = queryPacket.getPosition();
2049:
2050:                        queryStartTime = getCurrentTimeNanosOrMillis();
2051:                    }
2052:
2053:                    // Send query command and sql query string
2054:                    Buffer resultPacket = sendCommand(MysqlDefs.QUERY, null,
2055:                            queryPacket, false, null);
2056:
2057:                    long fetchBeginTime = 0;
2058:                    long fetchEndTime = 0;
2059:
2060:                    String profileQueryToLog = null;
2061:
2062:                    boolean queryWasSlow = false;
2063:
2064:                    if (this .profileSql || this .logSlowQueries) {
2065:                        queryEndTime = System.currentTimeMillis();
2066:
2067:                        boolean shouldExtractQuery = false;
2068:
2069:                        if (this .profileSql) {
2070:                            shouldExtractQuery = true;
2071:                        } else if (this .logSlowQueries
2072:                                && ((queryEndTime - queryStartTime) > this .connection
2073:                                        .getSlowQueryThresholdMillis())) {
2074:                            shouldExtractQuery = true;
2075:                            queryWasSlow = true;
2076:                        }
2077:
2078:                        if (shouldExtractQuery) {
2079:                            // Extract the actual query from the network packet
2080:                            boolean truncated = false;
2081:
2082:                            int extractPosition = oldPacketPosition;
2083:
2084:                            if (oldPacketPosition > this .connection
2085:                                    .getMaxQuerySizeToLog()) {
2086:                                extractPosition = this .connection
2087:                                        .getMaxQuerySizeToLog() + 5;
2088:                                truncated = true;
2089:                            }
2090:
2091:                            profileQueryToLog = new String(queryBuf, 5,
2092:                                    (extractPosition - 5));
2093:
2094:                            if (truncated) {
2095:                                profileQueryToLog += Messages
2096:                                        .getString("MysqlIO.25"); //$NON-NLS-1$
2097:                            }
2098:                        }
2099:
2100:                        fetchBeginTime = queryEndTime;
2101:                    }
2102:
2103:                    if (this .autoGenerateTestcaseScript) {
2104:                        String testcaseQuery = null;
2105:
2106:                        if (query != null) {
2107:                            testcaseQuery = query;
2108:                        } else {
2109:                            testcaseQuery = new String(queryBuf, 5,
2110:                                    (oldPacketPosition - 5));
2111:                        }
2112:
2113:                        StringBuffer debugBuf = new StringBuffer(testcaseQuery
2114:                                .length() + 32);
2115:                        this .connection
2116:                                .generateConnectionCommentBlock(debugBuf);
2117:                        debugBuf.append(testcaseQuery);
2118:                        debugBuf.append(';');
2119:                        this .connection.dumpTestcaseQuery(debugBuf.toString());
2120:                    }
2121:
2122:                    ResultSetInternalMethods rs = readAllResults(
2123:                            callingStatement, maxRows, resultSetType,
2124:                            resultSetConcurrency, streamResults, catalog,
2125:                            resultPacket, false, -1L, cachedMetadata);
2126:
2127:                    if (queryWasSlow) {
2128:                        StringBuffer mesgBuf = new StringBuffer(
2129:                                48 + profileQueryToLog.length());
2130:
2131:                        mesgBuf
2132:                                .append(Messages
2133:                                        .getString(
2134:                                                "MysqlIO.SlowQuery",
2135:                                                new Object[] {
2136:                                                        new Long(
2137:                                                                this .slowQueryThreshold),
2138:                                                        queryTimingUnits,
2139:                                                        new Long(
2140:                                                                queryEndTime
2141:                                                                        - queryStartTime) }));
2142:                        mesgBuf.append(profileQueryToLog);
2143:
2144:                        ProfileEventSink eventSink = ProfileEventSink
2145:                                .getInstance(this .connection);
2146:
2147:                        eventSink.consumeEvent(new ProfilerEvent(
2148:                                ProfilerEvent.TYPE_SLOW_QUERY,
2149:                                "", catalog, this .connection.getId(), //$NON-NLS-1$
2150:                                (callingStatement != null) ? callingStatement
2151:                                        .getId() : 999,
2152:                                ((ResultSetImpl) rs).resultId, System
2153:                                        .currentTimeMillis(),
2154:                                (int) (queryEndTime - queryStartTime),
2155:                                queryTimingUnits, null, new Throwable(),
2156:                                mesgBuf.toString()));
2157:
2158:                        if (this .connection.getExplainSlowQueries()) {
2159:                            if (oldPacketPosition < MAX_QUERY_SIZE_TO_EXPLAIN) {
2160:                                explainSlowQuery(queryPacket.getBytes(5,
2161:                                        (oldPacketPosition - 5)),
2162:                                        profileQueryToLog);
2163:                            } else {
2164:                                this .connection
2165:                                        .getLog()
2166:                                        .logWarn(
2167:                                                Messages
2168:                                                        .getString("MysqlIO.28") //$NON-NLS-1$
2169:                                                        + MAX_QUERY_SIZE_TO_EXPLAIN
2170:                                                        + Messages
2171:                                                                .getString("MysqlIO.29")); //$NON-NLS-1$
2172:                            }
2173:                        }
2174:                    }
2175:
2176:                    if (this .logSlowQueries) {
2177:
2178:                        ProfileEventSink eventSink = ProfileEventSink
2179:                                .getInstance(this .connection);
2180:
2181:                        if (this .queryBadIndexUsed) {
2182:                            eventSink
2183:                                    .consumeEvent(new ProfilerEvent(
2184:                                            ProfilerEvent.TYPE_SLOW_QUERY,
2185:                                            "", catalog, //$NON-NLS-1$
2186:                                            this .connection.getId(),
2187:                                            (callingStatement != null) ? callingStatement
2188:                                                    .getId()
2189:                                                    : 999,
2190:                                            ((ResultSetImpl) rs).resultId,
2191:                                            System.currentTimeMillis(),
2192:                                            (queryEndTime - queryStartTime),
2193:                                            this .queryTimingUnits, null,
2194:                                            new Throwable(), Messages
2195:                                                    .getString("MysqlIO.33") //$NON-NLS-1$
2196:                                                    + profileQueryToLog));
2197:                        }
2198:
2199:                        if (this .queryNoIndexUsed) {
2200:                            eventSink
2201:                                    .consumeEvent(new ProfilerEvent(
2202:                                            ProfilerEvent.TYPE_SLOW_QUERY,
2203:                                            "", catalog, //$NON-NLS-1$
2204:                                            this .connection.getId(),
2205:                                            (callingStatement != null) ? callingStatement
2206:                                                    .getId()
2207:                                                    : 999,
2208:                                            ((ResultSetImpl) rs).resultId,
2209:                                            System.currentTimeMillis(),
2210:                                            (queryEndTime - queryStartTime),
2211:                                            this .queryTimingUnits, null,
2212:                                            new Throwable(), Messages
2213:                                                    .getString("MysqlIO.35") //$NON-NLS-1$
2214:                                                    + profileQueryToLog));
2215:                        }
2216:                    }
2217:
2218:                    if (this .profileSql) {
2219:                        fetchEndTime = getCurrentTimeNanosOrMillis();
2220:
2221:                        ProfileEventSink eventSink = ProfileEventSink
2222:                                .getInstance(this .connection);
2223:
2224:                        eventSink.consumeEvent(new ProfilerEvent(
2225:                                ProfilerEvent.TYPE_QUERY,
2226:                                "", catalog, this .connection.getId(), //$NON-NLS-1$
2227:                                (callingStatement != null) ? callingStatement
2228:                                        .getId() : 999,
2229:                                ((ResultSetImpl) rs).resultId, System
2230:                                        .currentTimeMillis(),
2231:                                (queryEndTime - queryStartTime),
2232:                                this .queryTimingUnits, null, new Throwable(),
2233:                                profileQueryToLog));
2234:
2235:                        eventSink.consumeEvent(new ProfilerEvent(
2236:                                ProfilerEvent.TYPE_FETCH,
2237:                                "", catalog, this .connection.getId(), //$NON-NLS-1$
2238:                                (callingStatement != null) ? callingStatement
2239:                                        .getId() : 999,
2240:                                ((ResultSetImpl) rs).resultId, System
2241:                                        .currentTimeMillis(),
2242:                                (fetchEndTime - fetchBeginTime),
2243:                                this .queryTimingUnits, null, new Throwable(),
2244:                                null));
2245:                    }
2246:
2247:                    if (this .hadWarnings) {
2248:                        scanForAndThrowDataTruncation();
2249:                    }
2250:
2251:                    if (this .statementInterceptors != null) {
2252:                        ResultSetInternalMethods interceptedResults = invokeStatementInterceptorsPost(
2253:                                query, callingStatement, rs);
2254:
2255:                        if (interceptedResults != null) {
2256:                            rs = interceptedResults;
2257:                        }
2258:                    }
2259:
2260:                    return rs;
2261:                } finally {
2262:                    this .statementExecutionDepth--;
2263:                }
2264:            }
2265:
2266:            private ResultSetInternalMethods invokeStatementInterceptorsPre(
2267:                    String sql, Statement interceptedStatement)
2268:                    throws SQLException {
2269:                ResultSetInternalMethods previousResultSet = null;
2270:
2271:                Iterator interceptors = this .statementInterceptors.iterator();
2272:
2273:                while (interceptors.hasNext()) {
2274:                    StatementInterceptor interceptor = ((StatementInterceptor) interceptors
2275:                            .next());
2276:
2277:                    boolean executeTopLevelOnly = interceptor
2278:                            .executeTopLevelOnly();
2279:                    boolean shouldExecute = (executeTopLevelOnly && this .statementExecutionDepth == 1)
2280:                            || (!executeTopLevelOnly);
2281:
2282:                    if (shouldExecute) {
2283:                        String sqlToInterceptor = sql;
2284:
2285:                        if (interceptedStatement instanceof  PreparedStatement) {
2286:                            sqlToInterceptor = ((PreparedStatement) interceptedStatement)
2287:                                    .asSql();
2288:                        }
2289:
2290:                        ResultSetInternalMethods interceptedResultSet = interceptor
2291:                                .preProcess(sqlToInterceptor,
2292:                                        interceptedStatement, this .connection);
2293:
2294:                        if (interceptedResultSet != null) {
2295:                            previousResultSet = interceptedResultSet;
2296:                        }
2297:                    }
2298:                }
2299:
2300:                return previousResultSet;
2301:            }
2302:
2303:            private ResultSetInternalMethods invokeStatementInterceptorsPost(
2304:                    String sql, Statement interceptedStatement,
2305:                    ResultSetInternalMethods originalResultSet)
2306:                    throws SQLException {
2307:                Iterator interceptors = this .statementInterceptors.iterator();
2308:
2309:                while (interceptors.hasNext()) {
2310:                    StatementInterceptor interceptor = ((StatementInterceptor) interceptors
2311:                            .next());
2312:
2313:                    boolean executeTopLevelOnly = interceptor
2314:                            .executeTopLevelOnly();
2315:                    boolean shouldExecute = (executeTopLevelOnly && this .statementExecutionDepth == 1)
2316:                            || (!executeTopLevelOnly);
2317:
2318:                    if (shouldExecute) {
2319:                        String sqlToInterceptor = sql;
2320:
2321:                        if (interceptedStatement instanceof  PreparedStatement) {
2322:                            sqlToInterceptor = ((PreparedStatement) interceptedStatement)
2323:                                    .asSql();
2324:                        }
2325:
2326:                        ResultSetInternalMethods interceptedResultSet = interceptor
2327:                                .postProcess(sqlToInterceptor,
2328:                                        interceptedStatement,
2329:                                        originalResultSet, this .connection);
2330:
2331:                        if (interceptedResultSet != null) {
2332:                            originalResultSet = interceptedResultSet;
2333:                        }
2334:                    }
2335:                }
2336:
2337:                return originalResultSet;
2338:            }
2339:
2340:            private void calculateSlowQueryThreshold() {
2341:                this .slowQueryThreshold = this .connection
2342:                        .getSlowQueryThresholdMillis();
2343:
2344:                if (this .connection.getUseNanosForElapsedTime()) {
2345:                    long nanosThreshold = this .connection
2346:                            .getSlowQueryThresholdNanos();
2347:
2348:                    if (nanosThreshold != 0) {
2349:                        this .slowQueryThreshold = nanosThreshold;
2350:                    } else {
2351:                        this .slowQueryThreshold *= 1000000; // 1 million millis in a nano
2352:                    }
2353:                }
2354:            }
2355:
2356:            protected long getCurrentTimeNanosOrMillis() {
2357:                if (this .useNanosForElapsedTime) {
2358:                    return Util.getCurrentTimeNanosOrMillis();
2359:                }
2360:
2361:                return System.currentTimeMillis();
2362:            }
2363:
2364:            /**
2365:             * Returns the host this IO is connected to
2366:             *
2367:             * @return DOCUMENT ME!
2368:             */
2369:            String getHost() {
2370:                return this .host;
2371:            }
2372:
2373:            /**
2374:             * Is the version of the MySQL server we are connected to the given
2375:             * version?
2376:             *
2377:             * @param major the major version
2378:             * @param minor the minor version
2379:             * @param subminor the subminor version
2380:             *
2381:             * @return true if the version of the MySQL server we are connected  is the
2382:             *         given version
2383:             */
2384:            boolean isVersion(int major, int minor, int subminor) {
2385:                return ((major == getServerMajorVersion())
2386:                        && (minor == getServerMinorVersion()) && (subminor == getServerSubMinorVersion()));
2387:            }
2388:
2389:            /**
2390:             * Does the version of the MySQL server we are connected to meet the given
2391:             * minimums?
2392:             *
2393:             * @param major DOCUMENT ME!
2394:             * @param minor DOCUMENT ME!
2395:             * @param subminor DOCUMENT ME!
2396:             *
2397:             * @return DOCUMENT ME!
2398:             */
2399:            boolean versionMeetsMinimum(int major, int minor, int subminor) {
2400:                if (getServerMajorVersion() >= major) {
2401:                    if (getServerMajorVersion() == major) {
2402:                        if (getServerMinorVersion() >= minor) {
2403:                            if (getServerMinorVersion() == minor) {
2404:                                return (getServerSubMinorVersion() >= subminor);
2405:                            }
2406:
2407:                            // newer than major.minor
2408:                            return true;
2409:                        }
2410:
2411:                        // older than major.minor
2412:                        return false;
2413:                    }
2414:
2415:                    // newer than major
2416:                    return true;
2417:                }
2418:
2419:                return false;
2420:            }
2421:
2422:            /**
2423:             * Returns the hex dump of the given packet, truncated to
2424:             * MAX_PACKET_DUMP_LENGTH if packetLength exceeds that value.
2425:             *
2426:             * @param packetToDump the packet to dump in hex
2427:             * @param packetLength the number of bytes to dump
2428:             *
2429:             * @return the hex dump of the given packet
2430:             */
2431:            private final static String getPacketDumpToLog(Buffer packetToDump,
2432:                    int packetLength) {
2433:                if (packetLength < MAX_PACKET_DUMP_LENGTH) {
2434:                    return packetToDump.dump(packetLength);
2435:                }
2436:
2437:                StringBuffer packetDumpBuf = new StringBuffer(
2438:                        MAX_PACKET_DUMP_LENGTH * 4);
2439:                packetDumpBuf.append(packetToDump.dump(MAX_PACKET_DUMP_LENGTH));
2440:                packetDumpBuf.append(Messages.getString("MysqlIO.36")); //$NON-NLS-1$
2441:                packetDumpBuf.append(MAX_PACKET_DUMP_LENGTH);
2442:                packetDumpBuf.append(Messages.getString("MysqlIO.37")); //$NON-NLS-1$
2443:
2444:                return packetDumpBuf.toString();
2445:            }
2446:
2447:            private final int readFully(InputStream in, byte[] b, int off,
2448:                    int len) throws IOException {
2449:                if (len < 0) {
2450:                    throw new IndexOutOfBoundsException();
2451:                }
2452:
2453:                int n = 0;
2454:
2455:                while (n < len) {
2456:                    int count = in.read(b, off + n, len - n);
2457:
2458:                    if (count < 0) {
2459:                        throw new EOFException(Messages.getString(
2460:                                "MysqlIO.EOF", new Object[] { new Integer(len),
2461:                                        new Integer(n) }));
2462:                    }
2463:
2464:                    n += count;
2465:                }
2466:
2467:                return n;
2468:            }
2469:
2470:            private final long skipFully(InputStream in, long len)
2471:                    throws IOException {
2472:                if (len < 0) {
2473:                    throw new IOException("Negative skip length not allowed");
2474:                }
2475:
2476:                long n = 0;
2477:
2478:                while (n < len) {
2479:                    long count = in.skip(len - n);
2480:
2481:                    if (count < 0) {
2482:                        throw new EOFException(Messages.getString(
2483:                                "MysqlIO.EOF", new Object[] { new Long(len),
2484:                                        new Long(n) }));
2485:                    }
2486:
2487:                    n += count;
2488:                }
2489:
2490:                return n;
2491:            }
2492:
2493:            /**
2494:             * Reads one result set off of the wire, if the result is actually an
2495:             * update count, creates an update-count only result set.
2496:             *
2497:             * @param callingStatement DOCUMENT ME!
2498:             * @param maxRows the maximum rows to return in the result set.
2499:             * @param resultSetType scrollability
2500:             * @param resultSetConcurrency updatability
2501:             * @param streamResults should the driver leave the results on the wire,
2502:             *        and read them only when needed?
2503:             * @param catalog the catalog in use
2504:             * @param resultPacket the first packet of information in the result set
2505:             * @param isBinaryEncoded is this result set from a prepared statement?
2506:             * @param preSentColumnCount do we already know the number of columns?
2507:             * @param unpackFieldInfo should we unpack the field information?
2508:             *
2509:             * @return a result set that either represents the rows, or an update count
2510:             *
2511:             * @throws SQLException if an error occurs while reading the rows
2512:             */
2513:            private final ResultSetImpl readResultsForQueryOrUpdate(
2514:                    StatementImpl callingStatement, int maxRows,
2515:                    int resultSetType, int resultSetConcurrency,
2516:                    boolean streamResults, String catalog, Buffer resultPacket,
2517:                    boolean isBinaryEncoded, long preSentColumnCount,
2518:                    Field[] metadataFromCache) throws SQLException {
2519:                long columnCount = resultPacket.readFieldLength();
2520:
2521:                if (columnCount == 0) {
2522:                    return buildResultSetWithUpdates(callingStatement,
2523:                            resultPacket);
2524:                } else if (columnCount == Buffer.NULL_LENGTH) {
2525:                    String charEncoding = null;
2526:
2527:                    if (this .connection.getUseUnicode()) {
2528:                        charEncoding = this .connection.getEncoding();
2529:                    }
2530:
2531:                    String fileName = null;
2532:
2533:                    if (this .platformDbCharsetMatches) {
2534:                        fileName = ((charEncoding != null) ? resultPacket
2535:                                .readString(charEncoding) : resultPacket
2536:                                .readString());
2537:                    } else {
2538:                        fileName = resultPacket.readString();
2539:                    }
2540:
2541:                    return sendFileToServer(callingStatement, fileName);
2542:                } else {
2543:                    com.mysql.jdbc.ResultSetImpl results = getResultSet(
2544:                            callingStatement, columnCount, maxRows,
2545:                            resultSetType, resultSetConcurrency, streamResults,
2546:                            catalog, isBinaryEncoded, metadataFromCache);
2547:
2548:                    return results;
2549:                }
2550:            }
2551:
2552:            private int alignPacketSize(int a, int l) {
2553:                return ((((a) + (l)) - 1) & ~((l) - 1));
2554:            }
2555:
2556:            private com.mysql.jdbc.ResultSetImpl buildResultSetWithRows(
2557:                    StatementImpl callingStatement, String catalog,
2558:                    com.mysql.jdbc.Field[] fields, RowData rows,
2559:                    int resultSetType, int resultSetConcurrency,
2560:                    boolean isBinaryEncoded) throws SQLException {
2561:                ResultSetImpl rs = null;
2562:
2563:                switch (resultSetConcurrency) {
2564:                case java.sql.ResultSet.CONCUR_READ_ONLY:
2565:                    rs = com.mysql.jdbc.ResultSetImpl.getInstance(catalog,
2566:                            fields, rows, this .connection, callingStatement,
2567:                            false);
2568:
2569:                    if (isBinaryEncoded) {
2570:                        rs.setBinaryEncoded();
2571:                    }
2572:
2573:                    break;
2574:
2575:                case java.sql.ResultSet.CONCUR_UPDATABLE:
2576:                    rs = com.mysql.jdbc.ResultSetImpl.getInstance(catalog,
2577:                            fields, rows, this .connection, callingStatement,
2578:                            true);
2579:
2580:                    break;
2581:
2582:                default:
2583:                    return com.mysql.jdbc.ResultSetImpl.getInstance(catalog,
2584:                            fields, rows, this .connection, callingStatement,
2585:                            false);
2586:                }
2587:
2588:                rs.setResultSetType(resultSetType);
2589:                rs.setResultSetConcurrency(resultSetConcurrency);
2590:
2591:                return rs;
2592:            }
2593:
2594:            private com.mysql.jdbc.ResultSetImpl buildResultSetWithUpdates(
2595:                    StatementImpl callingStatement, Buffer resultPacket)
2596:                    throws SQLException {
2597:                long updateCount = -1;
2598:                long updateID = -1;
2599:                String info = null;
2600:
2601:                try {
2602:                    if (this .useNewUpdateCounts) {
2603:                        updateCount = resultPacket.newReadLength();
2604:                        updateID = resultPacket.newReadLength();
2605:                    } else {
2606:                        updateCount = resultPacket.readLength();
2607:                        updateID = resultPacket.readLength();
2608:                    }
2609:
2610:                    if (this .use41Extensions) {
2611:                        this .serverStatus = resultPacket.readInt();
2612:
2613:                        this .warningCount = resultPacket.readInt();
2614:
2615:                        if (this .warningCount > 0) {
2616:                            this .hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
2617:                        }
2618:
2619:                        resultPacket.readByte(); // advance pointer
2620:
2621:                        if (this .profileSql) {
2622:                            this .queryNoIndexUsed = (this .serverStatus & SERVER_QUERY_NO_GOOD_INDEX_USED) != 0;
2623:                            this .queryBadIndexUsed = (this .serverStatus & SERVER_QUERY_NO_INDEX_USED) != 0;
2624:                        }
2625:                    }
2626:
2627:                    if (this .connection.isReadInfoMsgEnabled()) {
2628:                        info = resultPacket.readString();
2629:                    }
2630:                } catch (Exception ex) {
2631:                    throw SQLError.createSQLException(SQLError
2632:                            .get(SQLError.SQL_STATE_GENERAL_ERROR)
2633:                            + ": " //$NON-NLS-1$
2634:                            + ex.getClass().getName(),
2635:                            SQLError.SQL_STATE_GENERAL_ERROR, -1);
2636:                }
2637:
2638:                ResultSetInternalMethods updateRs = com.mysql.jdbc.ResultSetImpl
2639:                        .getInstance(updateCount, updateID, this .connection,
2640:                                callingStatement);
2641:
2642:                if (info != null) {
2643:                    ((com.mysql.jdbc.ResultSetImpl) updateRs)
2644:                            .setServerInfo(info);
2645:                }
2646:
2647:                return (com.mysql.jdbc.ResultSetImpl) updateRs;
2648:            }
2649:
2650:            private void checkForOutstandingStreamingData() throws SQLException {
2651:                if (this .streamingData != null) {
2652:                    boolean shouldClobber = this .connection
2653:                            .getClobberStreamingResults();
2654:
2655:                    if (!shouldClobber) {
2656:                        throw SQLError.createSQLException(Messages
2657:                                .getString("MysqlIO.39") //$NON-NLS-1$
2658:                                + this .streamingData
2659:                                + Messages.getString("MysqlIO.40") //$NON-NLS-1$
2660:                                + Messages.getString("MysqlIO.41") //$NON-NLS-1$
2661:                                + Messages.getString("MysqlIO.42")); //$NON-NLS-1$
2662:                    }
2663:
2664:                    // Close the result set
2665:                    this .streamingData.getOwner().realClose(false);
2666:
2667:                    // clear any pending data....
2668:                    clearInputStream();
2669:                }
2670:            }
2671:
2672:            private Buffer compressPacket(Buffer packet, int offset,
2673:                    int packetLen, int headerLength) throws SQLException {
2674:                packet.writeLongInt(packetLen - headerLength);
2675:                packet.writeByte((byte) 0); // wrapped packet has 0 packet seq.
2676:
2677:                int lengthToWrite = 0;
2678:                int compressedLength = 0;
2679:                byte[] bytesToCompress = packet.getByteBuffer();
2680:                byte[] compressedBytes = null;
2681:                int offsetWrite = 0;
2682:
2683:                if (packetLen < MIN_COMPRESS_LEN) {
2684:                    lengthToWrite = packetLen;
2685:                    compressedBytes = packet.getByteBuffer();
2686:                    compressedLength = 0;
2687:                    offsetWrite = offset;
2688:                } else {
2689:                    compressedBytes = new byte[bytesToCompress.length * 2];
2690:
2691:                    this .deflater.reset();
2692:                    this .deflater.setInput(bytesToCompress, offset, packetLen);
2693:                    this .deflater.finish();
2694:
2695:                    int compLen = this .deflater.deflate(compressedBytes);
2696:
2697:                    if (compLen > packetLen) {
2698:                        lengthToWrite = packetLen;
2699:                        compressedBytes = packet.getByteBuffer();
2700:                        compressedLength = 0;
2701:                        offsetWrite = offset;
2702:                    } else {
2703:                        lengthToWrite = compLen;
2704:                        headerLength += COMP_HEADER_LENGTH;
2705:                        compressedLength = packetLen;
2706:                    }
2707:                }
2708:
2709:                Buffer compressedPacket = new Buffer(packetLen + headerLength);
2710:
2711:                compressedPacket.setPosition(0);
2712:                compressedPacket.writeLongInt(lengthToWrite);
2713:                compressedPacket.writeByte(this .packetSequence);
2714:                compressedPacket.writeLongInt(compressedLength);
2715:                compressedPacket.writeBytesNoNull(compressedBytes, offsetWrite,
2716:                        lengthToWrite);
2717:
2718:                return compressedPacket;
2719:            }
2720:
2721:            private final void readServerStatusForResultSets(Buffer rowPacket)
2722:                    throws SQLException {
2723:                if (this .use41Extensions) {
2724:                    rowPacket.readByte(); // skips the 'last packet' flag
2725:
2726:                    this .warningCount = rowPacket.readInt();
2727:
2728:                    if (this .warningCount > 0) {
2729:                        this .hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
2730:                    }
2731:
2732:                    this .serverStatus = rowPacket.readInt();
2733:
2734:                    if (this .profileSql) {
2735:                        this .queryNoIndexUsed = (this .serverStatus & SERVER_QUERY_NO_GOOD_INDEX_USED) != 0;
2736:                        this .queryBadIndexUsed = (this .serverStatus & SERVER_QUERY_NO_INDEX_USED) != 0;
2737:                    }
2738:                }
2739:            }
2740:
2741:            private SocketFactory createSocketFactory() throws SQLException {
2742:                try {
2743:                    if (this .socketFactoryClassName == null) {
2744:                        throw SQLError
2745:                                .createSQLException(
2746:                                        Messages.getString("MysqlIO.75"), //$NON-NLS-1$
2747:                                        SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
2748:                    }
2749:
2750:                    return (SocketFactory) (Class
2751:                            .forName(this .socketFactoryClassName).newInstance());
2752:                } catch (Exception ex) {
2753:                    throw SQLError.createSQLException(Messages
2754:                            .getString("MysqlIO.76") //$NON-NLS-1$
2755:                            + this .socketFactoryClassName
2756:                            + Messages.getString("MysqlIO.77") + ex.toString() //$NON-NLS-1$
2757:                            + (this .connection.getParanoid() ? "" //$NON-NLS-1$
2758:                                    : Util.stackTraceToString(ex)),
2759:                            SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
2760:                }
2761:            }
2762:
2763:            private void enqueuePacketForDebugging(boolean isPacketBeingSent,
2764:                    boolean isPacketReused, int sendLength, byte[] header,
2765:                    Buffer packet) throws SQLException {
2766:                if ((this .packetDebugRingBuffer.size() + 1) > this .connection
2767:                        .getPacketDebugBufferSize()) {
2768:                    this .packetDebugRingBuffer.removeFirst();
2769:                }
2770:
2771:                StringBuffer packetDump = null;
2772:
2773:                if (!isPacketBeingSent) {
2774:                    int bytesToDump = Math.min(MAX_PACKET_DUMP_LENGTH, packet
2775:                            .getBufLength());
2776:
2777:                    Buffer packetToDump = new Buffer(4 + bytesToDump);
2778:
2779:                    packetToDump.setPosition(0);
2780:                    packetToDump.writeBytesNoNull(header);
2781:                    packetToDump.writeBytesNoNull(packet.getBytes(0,
2782:                            bytesToDump));
2783:
2784:                    String packetPayload = packetToDump.dump(bytesToDump);
2785:
2786:                    packetDump = new StringBuffer(96 + packetPayload.length());
2787:
2788:                    packetDump.append("Server ");
2789:
2790:                    if (isPacketReused) {
2791:                        packetDump.append("(re-used)");
2792:                    } else {
2793:                        packetDump.append("(new)");
2794:                    }
2795:
2796:                    packetDump.append(" ");
2797:                    packetDump.append(packet.toSuperString());
2798:                    packetDump.append(" --------------------> Client\n");
2799:                    packetDump.append("\nPacket payload:\n\n");
2800:                    packetDump.append(packetPayload);
2801:
2802:                    if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
2803:                        packetDump.append("\nNote: Packet of "
2804:                                + packet.getBufLength()
2805:                                + " bytes truncated to "
2806:                                + MAX_PACKET_DUMP_LENGTH + " bytes.\n");
2807:                    }
2808:                } else {
2809:                    int bytesToDump = Math.min(MAX_PACKET_DUMP_LENGTH,
2810:                            sendLength);
2811:
2812:                    String packetPayload = packet.dump(bytesToDump);
2813:
2814:                    packetDump = new StringBuffer(64 + 4 + packetPayload
2815:                            .length());
2816:
2817:                    packetDump.append("Client ");
2818:                    packetDump.append(packet.toSuperString());
2819:                    packetDump.append("--------------------> Server\n");
2820:                    packetDump.append("\nPacket payload:\n\n");
2821:                    packetDump.append(packetPayload);
2822:
2823:                    if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
2824:                        packetDump.append("\nNote: Packet of " + sendLength
2825:                                + " bytes truncated to "
2826:                                + MAX_PACKET_DUMP_LENGTH + " bytes.\n");
2827:                    }
2828:                }
2829:
2830:                this .packetDebugRingBuffer.addLast(packetDump);
2831:            }
2832:
2833:            private RowData readSingleRowSet(long columnCount, int maxRows,
2834:                    int resultSetConcurrency, boolean isBinaryEncoded,
2835:                    Field[] fields) throws SQLException {
2836:                RowData rowData;
2837:                ArrayList rows = new ArrayList();
2838:
2839:                boolean useBufferRowExplicit = useBufferRowExplicit(fields);
2840:
2841:                // Now read the data
2842:                ResultSetRow row = nextRow(fields, (int) columnCount,
2843:                        isBinaryEncoded, resultSetConcurrency, false,
2844:                        useBufferRowExplicit, false, null);
2845:
2846:                int rowCount = 0;
2847:
2848:                if (row != null) {
2849:                    rows.add(row);
2850:                    rowCount = 1;
2851:                }
2852:
2853:                while (row != null) {
2854:                    row = nextRow(fields, (int) columnCount, isBinaryEncoded,
2855:                            resultSetConcurrency, false, useBufferRowExplicit,
2856:                            false, null);
2857:
2858:                    if (row != null) {
2859:                        if ((maxRows == -1) || (rowCount < maxRows)) {
2860:                            rows.add(row);
2861:                            rowCount++;
2862:                        }
2863:                    }
2864:                }
2865:
2866:                rowData = new RowDataStatic(rows);
2867:
2868:                return rowData;
2869:            }
2870:
2871:            public static boolean useBufferRowExplicit(Field[] fields) {
2872:                if (fields == null) {
2873:                    return false;
2874:                }
2875:
2876:                for (int i = 0; i < fields.length; i++) {
2877:                    switch (fields[i].getSQLType()) {
2878:                    case Types.BLOB:
2879:                    case Types.CLOB:
2880:                    case Types.LONGVARBINARY:
2881:                    case Types.LONGVARCHAR:
2882:                        return true;
2883:                    }
2884:                }
2885:
2886:                return false;
2887:            }
2888:
2889:            /**
2890:             * Don't hold on to overly-large packets
2891:             */
2892:            private void reclaimLargeReusablePacket() {
2893:                if ((this .reusablePacket != null)
2894:                        && (this .reusablePacket.getCapacity() > 1048576)) {
2895:                    this .reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
2896:                }
2897:            }
2898:
2899:            /**
2900:             * Re-use a packet to read from the MySQL server
2901:             *
2902:             * @param reuse DOCUMENT ME!
2903:             *
2904:             * @return DOCUMENT ME!
2905:             *
2906:             * @throws SQLException DOCUMENT ME!
2907:             * @throws SQLException DOCUMENT ME!
2908:             */
2909:            private final Buffer reuseAndReadPacket(Buffer reuse)
2910:                    throws SQLException {
2911:                return reuseAndReadPacket(reuse, -1);
2912:            }
2913:
2914:            private final Buffer reuseAndReadPacket(Buffer reuse,
2915:                    int existingPacketLength) throws SQLException {
2916:
2917:                try {
2918:                    reuse.setWasMultiPacket(false);
2919:                    int packetLength = 0;
2920:
2921:                    if (existingPacketLength == -1) {
2922:                        int lengthRead = readFully(this .mysqlInput,
2923:                                this .packetHeaderBuf, 0, 4);
2924:
2925:                        if (lengthRead < 4) {
2926:                            forceClose();
2927:                            throw new IOException(Messages
2928:                                    .getString("MysqlIO.43")); //$NON-NLS-1$
2929:                        }
2930:
2931:                        packetLength = (this .packetHeaderBuf[0] & 0xff)
2932:                                + ((this .packetHeaderBuf[1] & 0xff) << 8)
2933:                                + ((this .packetHeaderBuf[2] & 0xff) << 16);
2934:                    } else {
2935:                        packetLength = existingPacketLength;
2936:                    }
2937:
2938:                    if (this .traceProtocol) {
2939:                        StringBuffer traceMessageBuf = new StringBuffer();
2940:
2941:                        traceMessageBuf
2942:                                .append(Messages.getString("MysqlIO.44")); //$NON-NLS-1$
2943:                        traceMessageBuf.append(packetLength);
2944:                        traceMessageBuf
2945:                                .append(Messages.getString("MysqlIO.45")); //$NON-NLS-1$
2946:                        traceMessageBuf.append(StringUtils.dumpAsHex(
2947:                                this .packetHeaderBuf, 4));
2948:
2949:                        this .connection.getLog().logTrace(
2950:                                traceMessageBuf.toString());
2951:                    }
2952:
2953:                    byte multiPacketSeq = this .packetHeaderBuf[3];
2954:
2955:                    if (!this .packetSequenceReset) {
2956:                        if (this .enablePacketDebug && this .checkPacketSequence) {
2957:                            checkPacketSequencing(multiPacketSeq);
2958:                        }
2959:                    } else {
2960:                        this .packetSequenceReset = false;
2961:                    }
2962:
2963:                    this .readPacketSequence = multiPacketSeq;
2964:
2965:                    // Set the Buffer to it's original state
2966:                    reuse.setPosition(0);
2967:
2968:                    // Do we need to re-alloc the byte buffer?
2969:                    //
2970:                    // Note: We actually check the length of the buffer,
2971:                    // rather than getBufLength(), because getBufLength() is not
2972:                    // necesarily the actual length of the byte array
2973:                    // used as the buffer
2974:                    if (reuse.getByteBuffer().length <= packetLength) {
2975:                        reuse.setByteBuffer(new byte[packetLength + 1]);
2976:                    }
2977:
2978:                    // Set the new length
2979:                    reuse.setBufLength(packetLength);
2980:
2981:                    // Read the data from the server
2982:                    int numBytesRead = readFully(this .mysqlInput, reuse
2983:                            .getByteBuffer(), 0, packetLength);
2984:
2985:                    if (numBytesRead != packetLength) {
2986:                        throw new IOException("Short read, expected "
2987:                                + packetLength + " bytes, only read "
2988:                                + numBytesRead);
2989:                    }
2990:
2991:                    if (this .traceProtocol) {
2992:                        StringBuffer traceMessageBuf = new StringBuffer();
2993:
2994:                        traceMessageBuf
2995:                                .append(Messages.getString("MysqlIO.46")); //$NON-NLS-1$
2996:                        traceMessageBuf.append(getPacketDumpToLog(reuse,
2997:                                packetLength));
2998:
2999:                        this .connection.getLog().logTrace(
3000:                                traceMessageBuf.toString());
3001:                    }
3002:
3003:                    if (this .enablePacketDebug) {
3004:                        enqueuePacketForDebugging(false, true, 0,
3005:                                this .packetHeaderBuf, reuse);
3006:                    }
3007:
3008:                    boolean isMultiPacket = false;
3009:
3010:                    if (packetLength == this .maxThreeBytes) {
3011:                        reuse.setPosition(this .maxThreeBytes);
3012:
3013:                        int packetEndPoint = packetLength;
3014:
3015:                        // it's multi-packet
3016:                        isMultiPacket = true;
3017:
3018:                        packetLength = readRemainingMultiPackets(reuse,
3019:                                multiPacketSeq, packetEndPoint);
3020:                    }
3021:
3022:                    if (!isMultiPacket) {
3023:                        reuse.getByteBuffer()[packetLength] = 0; // Null-termination
3024:                    }
3025:
3026:                    return reuse;
3027:                } catch (IOException ioEx) {
3028:                    throw SQLError.createCommunicationsException(
3029:                            this .connection, this .lastPacketSentTimeMs, ioEx);
3030:                } catch (OutOfMemoryError oom) {
3031:                    try {
3032:                        // _Try_ this
3033:                        clearInputStream();
3034:                    } finally {
3035:                        try {
3036:                            this .connection.realClose(false, false, true, oom);
3037:                        } finally {
3038:                            throw oom;
3039:                        }
3040:                    }
3041:                }
3042:
3043:            }
3044:
3045:            private int readRemainingMultiPackets(Buffer reuse,
3046:                    byte multiPacketSeq, int packetEndPoint)
3047:                    throws IOException, SQLException {
3048:                int lengthRead;
3049:                int packetLength;
3050:                lengthRead = readFully(this .mysqlInput, this .packetHeaderBuf,
3051:                        0, 4);
3052:
3053:                if (lengthRead < 4) {
3054:                    forceClose();
3055:                    throw new IOException(Messages.getString("MysqlIO.47")); //$NON-NLS-1$
3056:                }
3057:
3058:                packetLength = (this .packetHeaderBuf[0] & 0xff)
3059:                        + ((this .packetHeaderBuf[1] & 0xff) << 8)
3060:                        + ((this .packetHeaderBuf[2] & 0xff) << 16);
3061:
3062:                Buffer multiPacket = new Buffer(packetLength);
3063:                boolean firstMultiPkt = true;
3064:
3065:                while (true) {
3066:                    if (!firstMultiPkt) {
3067:                        lengthRead = readFully(this .mysqlInput,
3068:                                this .packetHeaderBuf, 0, 4);
3069:
3070:                        if (lengthRead < 4) {
3071:                            forceClose();
3072:                            throw new IOException(Messages
3073:                                    .getString("MysqlIO.48")); //$NON-NLS-1$
3074:                        }
3075:
3076:                        packetLength = (this .packetHeaderBuf[0] & 0xff)
3077:                                + ((this .packetHeaderBuf[1] & 0xff) << 8)
3078:                                + ((this .packetHeaderBuf[2] & 0xff) << 16);
3079:                    } else {
3080:                        firstMultiPkt = false;
3081:                    }
3082:
3083:                    if (!this .useNewLargePackets && (packetLength == 1)) {
3084:                        clearInputStream();
3085:
3086:                        break;
3087:                    } else if (packetLength < this .maxThreeBytes) {
3088:                        byte newPacketSeq = this .packetHeaderBuf[3];
3089:
3090:                        if (newPacketSeq != (multiPacketSeq + 1)) {
3091:                            throw new IOException(Messages
3092:                                    .getString("MysqlIO.49")); //$NON-NLS-1$
3093:                        }
3094:
3095:                        multiPacketSeq = newPacketSeq;
3096:
3097:                        // Set the Buffer to it's original state
3098:                        multiPacket.setPosition(0);
3099:
3100:                        // Set the new length
3101:                        multiPacket.setBufLength(packetLength);
3102:
3103:                        // Read the data from the server
3104:                        byte[] byteBuf = multiPacket.getByteBuffer();
3105:                        int lengthToWrite = packetLength;
3106:
3107:                        int bytesRead = readFully(this .mysqlInput, byteBuf, 0,
3108:                                packetLength);
3109:
3110:                        if (bytesRead != lengthToWrite) {
3111:                            throw SQLError.createCommunicationsException(
3112:                                    this .connection, this .lastPacketSentTimeMs,
3113:                                    SQLError.createSQLException(Messages
3114:                                            .getString("MysqlIO.50") //$NON-NLS-1$
3115:                                            + lengthToWrite
3116:                                            + Messages.getString("MysqlIO.51")
3117:                                            + bytesRead //$NON-NLS-1$
3118:                                            + ".")); //$NON-NLS-1$
3119:                        }
3120:
3121:                        reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite);
3122:
3123:                        packetEndPoint += lengthToWrite;
3124:
3125:                        break; // end of multipacket sequence
3126:                    }
3127:
3128:                    byte newPacketSeq = this .packetHeaderBuf[3];
3129:
3130:                    if (newPacketSeq != (multiPacketSeq + 1)) {
3131:                        throw new IOException(Messages.getString("MysqlIO.53")); //$NON-NLS-1$
3132:                    }
3133:
3134:                    multiPacketSeq = newPacketSeq;
3135:
3136:                    // Set the Buffer to it's original state
3137:                    multiPacket.setPosition(0);
3138:
3139:                    // Set the new length
3140:                    multiPacket.setBufLength(packetLength);
3141:
3142:                    // Read the data from the server
3143:                    byte[] byteBuf = multiPacket.getByteBuffer();
3144:                    int lengthToWrite = packetLength;
3145:
3146:                    int bytesRead = readFully(this .mysqlInput, byteBuf, 0,
3147:                            packetLength);
3148:
3149:                    if (bytesRead != lengthToWrite) {
3150:                        throw SQLError.createCommunicationsException(
3151:                                this .connection, this .lastPacketSentTimeMs,
3152:                                SQLError.createSQLException(Messages
3153:                                        .getString("MysqlIO.54") //$NON-NLS-1$
3154:                                        + lengthToWrite
3155:                                        + Messages.getString("MysqlIO.55") //$NON-NLS-1$
3156:                                        + bytesRead + ".")); //$NON-NLS-1$
3157:                    }
3158:
3159:                    reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite);
3160:
3161:                    packetEndPoint += lengthToWrite;
3162:                }
3163:
3164:                reuse.setPosition(0);
3165:                reuse.setWasMultiPacket(true);
3166:                return packetLength;
3167:            }
3168:
3169:            /**
3170:             * @param multiPacketSeq
3171:             * @throws CommunicationsException
3172:             */
3173:            private void checkPacketSequencing(byte multiPacketSeq)
3174:                    throws SQLException {
3175:                if ((multiPacketSeq == -128)
3176:                        && (this .readPacketSequence != 127)) {
3177:                    throw SQLError.createCommunicationsException(
3178:                            this .connection, this .lastPacketSentTimeMs,
3179:                            new IOException(
3180:                                    "Packets out of order, expected packet # -128, but received packet # "
3181:                                            + multiPacketSeq));
3182:                }
3183:
3184:                if ((this .readPacketSequence == -1) && (multiPacketSeq != 0)) {
3185:                    throw SQLError.createCommunicationsException(
3186:                            this .connection, this .lastPacketSentTimeMs,
3187:                            new IOException(
3188:                                    "Packets out of order, expected packet # -1, but received packet # "
3189:                                            + multiPacketSeq));
3190:                }
3191:
3192:                if ((multiPacketSeq != -128) && (this .readPacketSequence != -1)
3193:                        && (multiPacketSeq != (this .readPacketSequence + 1))) {
3194:                    throw SQLError.createCommunicationsException(
3195:                            this .connection, this .lastPacketSentTimeMs,
3196:                            new IOException(
3197:                                    "Packets out of order, expected packet # "
3198:                                            + (this .readPacketSequence + 1)
3199:                                            + ", but received packet # "
3200:                                            + multiPacketSeq));
3201:                }
3202:            }
3203:
3204:            void enableMultiQueries() throws SQLException {
3205:                Buffer buf = getSharedSendPacket();
3206:
3207:                buf.clear();
3208:                buf.writeByte((byte) MysqlDefs.COM_SET_OPTION);
3209:                buf.writeInt(0);
3210:                sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null);
3211:            }
3212:
3213:            void disableMultiQueries() throws SQLException {
3214:                Buffer buf = getSharedSendPacket();
3215:
3216:                buf.clear();
3217:                buf.writeByte((byte) MysqlDefs.COM_SET_OPTION);
3218:                buf.writeInt(1);
3219:                sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null);
3220:            }
3221:
3222:            private final void send(Buffer packet, int packetLen)
3223:                    throws SQLException {
3224:                try {
3225:                    if (packetLen > this .maxAllowedPacket) {
3226:                        throw new PacketTooBigException(packetLen,
3227:                                this .maxAllowedPacket);
3228:                    }
3229:
3230:                    if (this .connection.getMaintainTimeStats()) {
3231:                        this .lastPacketSentTimeMs = System.currentTimeMillis();
3232:                    }
3233:
3234:                    if ((this .serverMajorVersion >= 4)
3235:                            && (packetLen >= this .maxThreeBytes)) {
3236:                        sendSplitPackets(packet);
3237:                    } else {
3238:                        this .packetSequence++;
3239:
3240:                        Buffer packetToSend = packet;
3241:
3242:                        packetToSend.setPosition(0);
3243:
3244:                        if (this .useCompression) {
3245:                            int originalPacketLen = packetLen;
3246:
3247:                            packetToSend = compressPacket(packet, 0, packetLen,
3248:                                    HEADER_LENGTH);
3249:                            packetLen = packetToSend.getPosition();
3250:
3251:                            if (this .traceProtocol) {
3252:                                StringBuffer traceMessageBuf = new StringBuffer();
3253:
3254:                                traceMessageBuf.append(Messages
3255:                                        .getString("MysqlIO.57")); //$NON-NLS-1$
3256:                                traceMessageBuf.append(getPacketDumpToLog(
3257:                                        packetToSend, packetLen));
3258:                                traceMessageBuf.append(Messages
3259:                                        .getString("MysqlIO.58")); //$NON-NLS-1$
3260:                                traceMessageBuf.append(getPacketDumpToLog(
3261:                                        packet, originalPacketLen));
3262:
3263:                                this .connection.getLog().logTrace(
3264:                                        traceMessageBuf.toString());
3265:                            }
3266:                        } else {
3267:                            packetToSend
3268:                                    .writeLongInt(packetLen - HEADER_LENGTH);
3269:                            packetToSend.writeByte(this .packetSequence);
3270:
3271:                            if (this .traceProtocol) {
3272:                                StringBuffer traceMessageBuf = new StringBuffer();
3273:
3274:                                traceMessageBuf.append(Messages
3275:                                        .getString("MysqlIO.59")); //$NON-NLS-1$
3276:                                traceMessageBuf.append(packetToSend
3277:                                        .dump(packetLen));
3278:
3279:                                this .connection.getLog().logTrace(
3280:                                        traceMessageBuf.toString());
3281:                            }
3282:                        }
3283:
3284:                        this .mysqlOutput.write(packetToSend.getByteBuffer(), 0,
3285:                                packetLen);
3286:                        this .mysqlOutput.flush();
3287:                    }
3288:
3289:                    if (this .enablePacketDebug) {
3290:                        enqueuePacketForDebugging(true, false, packetLen + 5,
3291:                                this .packetHeaderBuf, packet);
3292:                    }
3293:
3294:                    //
3295:                    // Don't hold on to large packets
3296:                    //
3297:                    if (packet == this .sharedSendPacket) {
3298:                        reclaimLargeSharedSendPacket();
3299:                    }
3300:                } catch (IOException ioEx) {
3301:                    throw SQLError.createCommunicationsException(
3302:                            this .connection, this .lastPacketSentTimeMs, ioEx);
3303:                }
3304:            }
3305:
3306:            /**
3307:             * Reads and sends a file to the server for LOAD DATA LOCAL INFILE
3308:             *
3309:             * @param callingStatement DOCUMENT ME!
3310:             * @param fileName the file name to send.
3311:             *
3312:             * @return DOCUMENT ME!
3313:             *
3314:             * @throws SQLException DOCUMENT ME!
3315:             */
3316:            private final ResultSetImpl sendFileToServer(
3317:                    StatementImpl callingStatement, String fileName)
3318:                    throws SQLException {
3319:
3320:                Buffer filePacket = (this .loadFileBufRef == null) ? null
3321:                        : (Buffer) (this .loadFileBufRef.get());
3322:
3323:                int bigPacketLength = Math.min(this .connection
3324:                        .getMaxAllowedPacket()
3325:                        - (HEADER_LENGTH * 3), alignPacketSize(this .connection
3326:                        .getMaxAllowedPacket() - 16, 4096)
3327:                        - (HEADER_LENGTH * 3));
3328:
3329:                int oneMeg = 1024 * 1024;
3330:
3331:                int smallerPacketSizeAligned = Math.min(oneMeg
3332:                        - (HEADER_LENGTH * 3), alignPacketSize(oneMeg - 16,
3333:                        4096)
3334:                        - (HEADER_LENGTH * 3));
3335:
3336:                int packetLength = Math.min(smallerPacketSizeAligned,
3337:                        bigPacketLength);
3338:
3339:                if (filePacket == null) {
3340:                    try {
3341:                        filePacket = new Buffer((packetLength + HEADER_LENGTH));
3342:                        this .loadFileBufRef = new SoftReference(filePacket);
3343:                    } catch (OutOfMemoryError oom) {
3344:                        throw SQLError
3345:                                .createSQLException(
3346:                                        "Could not allocate packet of "
3347:                                                + packetLength
3348:                                                + " bytes required for LOAD DATA LOCAL INFILE operation."
3349:                                                + " Try increasing max heap allocation for JVM or decreasing server variable "
3350:                                                + "'max_allowed_packet'",
3351:                                        SQLError.SQL_STATE_MEMORY_ALLOCATION_FAILURE);
3352:
3353:                    }
3354:                }
3355:
3356:                filePacket.clear();
3357:                send(filePacket, 0);
3358:
3359:                byte[] fileBuf = new byte[packetLength];
3360:
3361:                BufferedInputStream fileIn = null;
3362:
3363:                try {
3364:                    if (!this .connection.getAllowLoadLocalInfile()) {
3365:                        throw SQLError.createSQLException(Messages
3366:                                .getString("MysqlIO.LoadDataLocalNotAllowed"),
3367:                                SQLError.SQL_STATE_GENERAL_ERROR);
3368:                    }
3369:
3370:                    InputStream hookedStream = null;
3371:
3372:                    if (callingStatement != null) {
3373:                        hookedStream = callingStatement
3374:                                .getLocalInfileInputStream();
3375:                    }
3376:
3377:                    if (hookedStream != null) {
3378:                        fileIn = new BufferedInputStream(hookedStream);
3379:                    } else if (!this .connection.getAllowUrlInLocalInfile()) {
3380:                        fileIn = new BufferedInputStream(new FileInputStream(
3381:                                fileName));
3382:                    } else {
3383:                        // First look for ':'
3384:                        if (fileName.indexOf(':') != -1) {
3385:                            try {
3386:                                URL urlFromFileName = new URL(fileName);
3387:                                fileIn = new BufferedInputStream(
3388:                                        urlFromFileName.openStream());
3389:                            } catch (MalformedURLException badUrlEx) {
3390:                                // we fall back to trying this as a file input stream
3391:                                fileIn = new BufferedInputStream(
3392:                                        new FileInputStream(fileName));
3393:                            }
3394:                        } else {
3395:                            fileIn = new BufferedInputStream(
3396:                                    new FileInputStream(fileName));
3397:                        }
3398:                    }
3399:
3400:                    int bytesRead = 0;
3401:
3402:                    while ((bytesRead = fileIn.read(fileBuf)) != -1) {
3403:                        filePacket.clear();
3404:                        filePacket.writeBytesNoNull(fileBuf, 0, bytesRead);
3405:                        send(filePacket, filePacket.getPosition());
3406:                    }
3407:                } catch (IOException ioEx) {
3408:                    StringBuffer messageBuf = new StringBuffer(Messages
3409:                            .getString("MysqlIO.60")); //$NON-NLS-1$
3410:
3411:                    if (!this .connection.getParanoid()) {
3412:                        messageBuf.append("'"); //$NON-NLS-1$
3413:
3414:                        if (fileName != null) {
3415:                            messageBuf.append(fileName);
3416:                        }
3417:
3418:                        messageBuf.append("'"); //$NON-NLS-1$
3419:                    }
3420:
3421:                    messageBuf.append(Messages.getString("MysqlIO.63")); //$NON-NLS-1$
3422:
3423:                    if (!this .connection.getParanoid()) {
3424:                        messageBuf.append(Messages.getString("MysqlIO.64")); //$NON-NLS-1$
3425:                        messageBuf.append(Util.stackTraceToString(ioEx));
3426:                    }
3427:
3428:                    throw SQLError.createSQLException(messageBuf.toString(),
3429:                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3430:                } finally {
3431:                    if (fileIn != null) {
3432:                        try {
3433:                            fileIn.close();
3434:                        } catch (Exception ex) {
3435:                            throw SQLError.createSQLException(Messages
3436:                                    .getString("MysqlIO.65"), //$NON-NLS-1$
3437:                                    SQLError.SQL_STATE_GENERAL_ERROR);
3438:                        }
3439:
3440:                        fileIn = null;
3441:                    } else {
3442:                        // file open failed, but server needs one packet
3443:                        filePacket.clear();
3444:                        send(filePacket, filePacket.getPosition());
3445:                        checkErrorPacket(); // to clear response off of queue
3446:                    }
3447:                }
3448:
3449:                // send empty packet to mark EOF
3450:                filePacket.clear();
3451:                send(filePacket, filePacket.getPosition());
3452:
3453:                Buffer resultPacket = checkErrorPacket();
3454:
3455:                return buildResultSetWithUpdates(callingStatement, resultPacket);
3456:            }
3457:
3458:            /**
3459:             * Checks for errors in the reply packet, and if none, returns the reply
3460:             * packet, ready for reading
3461:             *
3462:             * @param command the command being issued (if used)
3463:             *
3464:             * @return DOCUMENT ME!
3465:             *
3466:             * @throws SQLException if an error packet was received
3467:             * @throws CommunicationsException DOCUMENT ME!
3468:             */
3469:            private Buffer checkErrorPacket(int command) throws SQLException {
3470:                int statusCode = 0;
3471:                Buffer resultPacket = null;
3472:                this .serverStatus = 0;
3473:
3474:                try {
3475:                    // Check return value, if we get a java.io.EOFException,
3476:                    // the server has gone away. We'll pass it on up the
3477:                    // exception chain and let someone higher up decide
3478:                    // what to do (barf, reconnect, etc).
3479:                    resultPacket = reuseAndReadPacket(this .reusablePacket);
3480:                } catch (SQLException sqlEx) {
3481:                    // Don't wrap SQL Exceptions
3482:                    throw sqlEx;
3483:                } catch (Exception fallThru) {
3484:                    throw SQLError.createCommunicationsException(
3485:                            this .connection, this .lastPacketSentTimeMs,
3486:                            fallThru);
3487:                }
3488:
3489:                checkErrorPacket(resultPacket);
3490:
3491:                return resultPacket;
3492:            }
3493:
3494:            private void checkErrorPacket(Buffer resultPacket)
3495:                    throws SQLException {
3496:
3497:                int statusCode = resultPacket.readByte();
3498:
3499:                // Error handling
3500:                if (statusCode == (byte) 0xff) {
3501:                    String serverErrorMessage;
3502:                    int errno = 2000;
3503:
3504:                    if (this .protocolVersion > 9) {
3505:                        errno = resultPacket.readInt();
3506:
3507:                        String xOpen = null;
3508:
3509:                        serverErrorMessage = resultPacket
3510:                                .readString(this .connection
3511:                                        .getErrorMessageEncoding());
3512:
3513:                        if (serverErrorMessage.charAt(0) == '#') { //$NON-NLS-1$
3514:
3515:                            // we have an SQLState
3516:                            if (serverErrorMessage.length() > 6) {
3517:                                xOpen = serverErrorMessage.substring(1, 6);
3518:                                serverErrorMessage = serverErrorMessage
3519:                                        .substring(6);
3520:
3521:                                if (xOpen.equals("HY000")) { //$NON-NLS-1$
3522:                                    xOpen = SQLError.mysqlToSqlState(errno,
3523:                                            this .connection
3524:                                                    .getUseSqlStateCodes());
3525:                                }
3526:                            } else {
3527:                                xOpen = SQLError.mysqlToSqlState(errno,
3528:                                        this .connection.getUseSqlStateCodes());
3529:                            }
3530:                        } else {
3531:                            xOpen = SQLError.mysqlToSqlState(errno,
3532:                                    this .connection.getUseSqlStateCodes());
3533:                        }
3534:
3535:                        clearInputStream();
3536:
3537:                        StringBuffer errorBuf = new StringBuffer();
3538:
3539:                        String xOpenErrorMessage = SQLError.get(xOpen);
3540:
3541:                        if (!this .connection.getUseOnlyServerErrorMessages()) {
3542:                            if (xOpenErrorMessage != null) {
3543:                                errorBuf.append(xOpenErrorMessage);
3544:                                errorBuf.append(Messages
3545:                                        .getString("MysqlIO.68")); //$NON-NLS-1$
3546:                            }
3547:                        }
3548:
3549:                        errorBuf.append(serverErrorMessage);
3550:
3551:                        if (!this .connection.getUseOnlyServerErrorMessages()) {
3552:                            if (xOpenErrorMessage != null) {
3553:                                errorBuf.append("\""); //$NON-NLS-1$
3554:                            }
3555:                        }
3556:
3557:                        appendInnodbStatusInformation(xOpen, errorBuf);
3558:
3559:                        if (xOpen != null && xOpen.startsWith("22")) {
3560:                            throw new MysqlDataTruncation(errorBuf.toString(),
3561:                                    0, true, false, 0, 0);
3562:                        } else {
3563:                            throw SQLError.createSQLException(errorBuf
3564:                                    .toString(), xOpen, errno);
3565:                        }
3566:                    }
3567:
3568:                    serverErrorMessage = resultPacket
3569:                            .readString(this .connection
3570:                                    .getErrorMessageEncoding());
3571:                    clearInputStream();
3572:
3573:                    if (serverErrorMessage.indexOf(Messages
3574:                            .getString("MysqlIO.70")) != -1) { //$NON-NLS-1$
3575:                        throw SQLError.createSQLException(SQLError
3576:                                .get(SQLError.SQL_STATE_COLUMN_NOT_FOUND)
3577:                                + ", " //$NON-NLS-1$
3578:                                + serverErrorMessage,
3579:                                SQLError.SQL_STATE_COLUMN_NOT_FOUND, -1);
3580:                    }
3581:
3582:                    StringBuffer errorBuf = new StringBuffer(Messages
3583:                            .getString("MysqlIO.72")); //$NON-NLS-1$
3584:                    errorBuf.append(serverErrorMessage);
3585:                    errorBuf.append("\""); //$NON-NLS-1$
3586:
3587:                    throw SQLError.createSQLException(SQLError
3588:                            .get(SQLError.SQL_STATE_GENERAL_ERROR)
3589:                            + ", " //$NON-NLS-1$
3590:                            + errorBuf.toString(),
3591:                            SQLError.SQL_STATE_GENERAL_ERROR, -1);
3592:                }
3593:            }
3594:
3595:            private void appendInnodbStatusInformation(String xOpen,
3596:                    StringBuffer errorBuf) throws SQLException {
3597:                if (this .connection
3598:                        .getIncludeInnodbStatusInDeadlockExceptions()
3599:                        && xOpen != null
3600:                        && (xOpen.startsWith("40") || xOpen.startsWith("41"))
3601:                        && this .streamingData == null) {
3602:                    ResultSet rs = null;
3603:
3604:                    try {
3605:                        rs = sqlQueryDirect(null, "SHOW ENGINE INNODB STATUS",
3606:                                this .connection.getEncoding(), null, -1,
3607:                                ResultSet.TYPE_FORWARD_ONLY,
3608:                                ResultSet.CONCUR_READ_ONLY, false,
3609:                                this .connection.getCatalog(), null);
3610:
3611:                        if (rs.next()) {
3612:                            errorBuf.append("\n\n");
3613:                            errorBuf.append(rs.getString(1));
3614:                        } else {
3615:                            errorBuf.append(Messages
3616:                                    .getString("MysqlIO.NoInnoDBStatusFound"));
3617:                        }
3618:                    } catch (Exception ex) {
3619:                        errorBuf.append(Messages
3620:                                .getString("MysqlIO.InnoDBStatusFailed"));
3621:                        errorBuf.append("\n\n");
3622:                        errorBuf.append(Util.stackTraceToString(ex));
3623:                    } finally {
3624:                        if (rs != null) {
3625:                            rs.close();
3626:                        }
3627:                    }
3628:                }
3629:            }
3630:
3631:            /**
3632:             * Sends a large packet to the server as a series of smaller packets
3633:             *
3634:             * @param packet DOCUMENT ME!
3635:             *
3636:             * @throws SQLException DOCUMENT ME!
3637:             * @throws CommunicationsException DOCUMENT ME!
3638:             */
3639:            private final void sendSplitPackets(Buffer packet)
3640:                    throws SQLException {
3641:                try {
3642:                    //
3643:                    // Big packets are handled by splitting them in packets of MAX_THREE_BYTES
3644:                    // length. The last packet is always a packet that is < MAX_THREE_BYTES.
3645:                    // (The last packet may even have a length of 0)
3646:                    //
3647:                    //
3648:                    // NB: Guarded by execSQL. If the driver changes architecture, this
3649:                    // will need to be synchronized in some other way
3650:                    //
3651:                    Buffer headerPacket = (this .splitBufRef == null) ? null
3652:                            : (Buffer) (this .splitBufRef.get());
3653:
3654:                    //
3655:                    // Store this packet in a soft reference...It can be re-used if not GC'd (so clients
3656:                    // that use it frequently won't have to re-alloc the 16M buffer), but we don't
3657:                    // penalize infrequent users of large packets by keeping 16M allocated all of the time
3658:                    //
3659:                    if (headerPacket == null) {
3660:                        headerPacket = new Buffer(
3661:                                (this .maxThreeBytes + HEADER_LENGTH));
3662:                        this .splitBufRef = new SoftReference(headerPacket);
3663:                    }
3664:
3665:                    int len = packet.getPosition();
3666:                    int splitSize = this .maxThreeBytes;
3667:                    int originalPacketPos = HEADER_LENGTH;
3668:                    byte[] origPacketBytes = packet.getByteBuffer();
3669:                    byte[] headerPacketBytes = headerPacket.getByteBuffer();
3670:
3671:                    while (len >= this .maxThreeBytes) {
3672:                        this .packetSequence++;
3673:
3674:                        headerPacket.setPosition(0);
3675:                        headerPacket.writeLongInt(splitSize);
3676:
3677:                        headerPacket.writeByte(this .packetSequence);
3678:                        System.arraycopy(origPacketBytes, originalPacketPos,
3679:                                headerPacketBytes, 4, splitSize);
3680:
3681:                        int packetLen = splitSize + HEADER_LENGTH;
3682:
3683:                        //
3684:                        // Swap a compressed packet in, if we're using
3685:                        // compression...
3686:                        //
3687:                        if (!this .useCompression) {
3688:                            this .mysqlOutput.write(headerPacketBytes, 0,
3689:                                    splitSize + HEADER_LENGTH);
3690:                            this .mysqlOutput.flush();
3691:                        } else {
3692:                            Buffer packetToSend;
3693:
3694:                            headerPacket.setPosition(0);
3695:                            packetToSend = compressPacket(headerPacket,
3696:                                    HEADER_LENGTH, splitSize, HEADER_LENGTH);
3697:                            packetLen = packetToSend.getPosition();
3698:
3699:                            this .mysqlOutput.write(
3700:                                    packetToSend.getByteBuffer(), 0, packetLen);
3701:                            this .mysqlOutput.flush();
3702:                        }
3703:
3704:                        originalPacketPos += splitSize;
3705:                        len -= splitSize;
3706:                    }
3707:
3708:                    //
3709:                    // Write last packet
3710:                    //
3711:                    headerPacket.clear();
3712:                    headerPacket.setPosition(0);
3713:                    headerPacket.writeLongInt(len - HEADER_LENGTH);
3714:                    this .packetSequence++;
3715:                    headerPacket.writeByte(this .packetSequence);
3716:
3717:                    if (len != 0) {
3718:                        System.arraycopy(origPacketBytes, originalPacketPos,
3719:                                headerPacketBytes, 4, len - HEADER_LENGTH);
3720:                    }
3721:
3722:                    int packetLen = len - HEADER_LENGTH;
3723:
3724:                    //
3725:                    // Swap a compressed packet in, if we're using
3726:                    // compression...
3727:                    //
3728:                    if (!this .useCompression) {
3729:                        this .mysqlOutput.write(headerPacket.getByteBuffer(), 0,
3730:                                len);
3731:                        this .mysqlOutput.flush();
3732:                    } else {
3733:                        Buffer packetToSend;
3734:
3735:                        headerPacket.setPosition(0);
3736:                        packetToSend = compressPacket(headerPacket,
3737:                                HEADER_LENGTH, packetLen, HEADER_LENGTH);
3738:                        packetLen = packetToSend.getPosition();
3739:
3740:                        this .mysqlOutput.write(packetToSend.getByteBuffer(), 0,
3741:                                packetLen);
3742:                        this .mysqlOutput.flush();
3743:                    }
3744:                } catch (IOException ioEx) {
3745:                    throw SQLError.createCommunicationsException(
3746:                            this .connection, this .lastPacketSentTimeMs, ioEx);
3747:                }
3748:            }
3749:
3750:            private void reclaimLargeSharedSendPacket() {
3751:                if ((this .sharedSendPacket != null)
3752:                        && (this .sharedSendPacket.getCapacity() > 1048576)) {
3753:                    this .sharedSendPacket = new Buffer(INITIAL_PACKET_SIZE);
3754:                }
3755:            }
3756:
3757:            boolean hadWarnings() {
3758:                return this .hadWarnings;
3759:            }
3760:
3761:            void scanForAndThrowDataTruncation() throws SQLException {
3762:                if ((this .streamingData == null)
3763:                        && versionMeetsMinimum(4, 1, 0)
3764:                        && this .connection.getJdbcCompliantTruncation()
3765:                        && this .warningCount > 0) {
3766:                    SQLError.convertShowWarningsToSQLWarnings(this .connection,
3767:                            this .warningCount, true);
3768:                }
3769:            }
3770:
3771:            /**
3772:             * Secure authentication for 4.1 and newer servers.
3773:             *
3774:             * @param packet DOCUMENT ME!
3775:             * @param packLength
3776:             * @param user
3777:             * @param password
3778:             * @param database DOCUMENT ME!
3779:             * @param writeClientParams
3780:             *
3781:             * @throws SQLException
3782:             */
3783:            private void secureAuth(Buffer packet, int packLength, String user,
3784:                    String password, String database, boolean writeClientParams)
3785:                    throws SQLException {
3786:                // Passwords can be 16 chars long
3787:                if (packet == null) {
3788:                    packet = new Buffer(packLength);
3789:                }
3790:
3791:                if (writeClientParams) {
3792:                    if (this .use41Extensions) {
3793:                        if (versionMeetsMinimum(4, 1, 1)) {
3794:                            packet.writeLong(this .clientParam);
3795:                            packet.writeLong(this .maxThreeBytes);
3796:
3797:                            // charset, JDBC will connect as 'latin1',
3798:                            // and use 'SET NAMES' to change to the desired
3799:                            // charset after the connection is established.
3800:                            packet.writeByte((byte) 8);
3801:
3802:                            // Set of bytes reserved for future use.
3803:                            packet.writeBytesNoNull(new byte[23]);
3804:                        } else {
3805:                            packet.writeLong(this .clientParam);
3806:                            packet.writeLong(this .maxThreeBytes);
3807:                        }
3808:                    } else {
3809:                        packet.writeInt((int) this .clientParam);
3810:                        packet.writeLongInt(this .maxThreeBytes);
3811:                    }
3812:                }
3813:
3814:                // User/Password data
3815:                packet.writeString(user, CODE_PAGE_1252, this .connection);
3816:
3817:                if (password.length() != 0) {
3818:                    /* Prepare false scramble  */
3819:                    packet.writeString(FALSE_SCRAMBLE, CODE_PAGE_1252,
3820:                            this .connection);
3821:                } else {
3822:                    /* For empty password*/
3823:                    packet.writeString("", CODE_PAGE_1252, this .connection); //$NON-NLS-1$
3824:                }
3825:
3826:                if (this .useConnectWithDb) {
3827:                    packet.writeString(database, CODE_PAGE_1252,
3828:                            this .connection);
3829:                }
3830:
3831:                send(packet, packet.getPosition());
3832:
3833:                //
3834:                // Don't continue stages if password is empty
3835:                //
3836:                if (password.length() > 0) {
3837:                    Buffer b = readPacket();
3838:
3839:                    b.setPosition(0);
3840:
3841:                    byte[] replyAsBytes = b.getByteBuffer();
3842:
3843:                    if ((replyAsBytes.length == 25) && (replyAsBytes[0] != 0)) {
3844:                        // Old passwords will have '*' at the first byte of hash */
3845:                        if (replyAsBytes[0] != '*') {
3846:                            try {
3847:                                /* Build full password hash as it is required to decode scramble */
3848:                                byte[] buff = Security
3849:                                        .passwordHashStage1(password);
3850:
3851:                                /* Store copy as we'll need it later */
3852:                                byte[] passwordHash = new byte[buff.length];
3853:                                System.arraycopy(buff, 0, passwordHash, 0,
3854:                                        buff.length);
3855:
3856:                                /* Finally hash complete password using hash we got from server */
3857:                                passwordHash = Security.passwordHashStage2(
3858:                                        passwordHash, replyAsBytes);
3859:
3860:                                byte[] packetDataAfterSalt = new byte[replyAsBytes.length - 5];
3861:
3862:                                System.arraycopy(replyAsBytes, 4,
3863:                                        packetDataAfterSalt, 0,
3864:                                        replyAsBytes.length - 5);
3865:
3866:                                byte[] mysqlScrambleBuff = new byte[20];
3867:
3868:                                /* Decypt and store scramble 4 = hash for stage2 */
3869:                                Security.passwordCrypt(packetDataAfterSalt,
3870:                                        mysqlScrambleBuff, passwordHash, 20);
3871:
3872:                                /* Encode scramble with password. Recycle buffer */
3873:                                Security.passwordCrypt(mysqlScrambleBuff, buff,
3874:                                        buff, 20);
3875:
3876:                                Buffer packet2 = new Buffer(25);
3877:                                packet2.writeBytesNoNull(buff);
3878:
3879:                                this .packetSequence++;
3880:
3881:                                send(packet2, 24);
3882:                            } catch (NoSuchAlgorithmException nse) {
3883:                                throw SQLError.createSQLException(Messages
3884:                                        .getString("MysqlIO.91") //$NON-NLS-1$
3885:                                        + Messages.getString("MysqlIO.92"), //$NON-NLS-1$
3886:                                        SQLError.SQL_STATE_GENERAL_ERROR);
3887:                            }
3888:                        } else {
3889:                            try {
3890:                                /* Create password to decode scramble */
3891:                                byte[] passwordHash = Security
3892:                                        .createKeyFromOldPassword(password);
3893:
3894:                                /* Decypt and store scramble 4 = hash for stage2 */
3895:                                byte[] netReadPos4 = new byte[replyAsBytes.length - 5];
3896:
3897:                                System.arraycopy(replyAsBytes, 4, netReadPos4,
3898:                                        0, replyAsBytes.length - 5);
3899:
3900:                                byte[] mysqlScrambleBuff = new byte[20];
3901:
3902:                                /* Decypt and store scramble 4 = hash for stage2 */
3903:                                Security.passwordCrypt(netReadPos4,
3904:                                        mysqlScrambleBuff, passwordHash, 20);
3905:
3906:                                /* Finally scramble decoded scramble with password */
3907:                                String scrambledPassword = Util
3908:                                        .scramble(
3909:                                                new String(mysqlScrambleBuff),
3910:                                                password);
3911:
3912:                                Buffer packet2 = new Buffer(packLength);
3913:                                packet2.writeString(scrambledPassword,
3914:                                        CODE_PAGE_1252, this .connection);
3915:                                this .packetSequence++;
3916:
3917:                                send(packet2, 24);
3918:                            } catch (NoSuchAlgorithmException nse) {
3919:                                throw SQLError.createSQLException(Messages
3920:                                        .getString("MysqlIO.93") //$NON-NLS-1$
3921:                                        + Messages.getString("MysqlIO.94"), //$NON-NLS-1$
3922:                                        SQLError.SQL_STATE_GENERAL_ERROR);
3923:                            }
3924:                        }
3925:                    }
3926:                }
3927:            }
3928:
3929:            /**
3930:             * Secure authentication for 4.1.1 and newer servers.
3931:             *
3932:             * @param packet DOCUMENT ME!
3933:             * @param packLength
3934:             * @param user
3935:             * @param password
3936:             * @param database DOCUMENT ME!
3937:             * @param writeClientParams
3938:             *
3939:             * @throws SQLException
3940:             */
3941:            void secureAuth411(Buffer packet, int packLength, String user,
3942:                    String password, String database, boolean writeClientParams)
3943:                    throws SQLException {
3944:                //	SERVER:  public_seed=create_random_string()
3945:                //			 send(public_seed)
3946:                //
3947:                //	CLIENT:  recv(public_seed)
3948:                //			 hash_stage1=sha1("password")
3949:                //			 hash_stage2=sha1(hash_stage1)
3950:                //			 reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
3951:                //
3952:                //			 // this three steps are done in scramble()
3953:                //
3954:                //			 send(reply)
3955:                //
3956:                //
3957:                //	SERVER:  recv(reply)
3958:                //			 hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
3959:                //			 candidate_hash2=sha1(hash_stage1)
3960:                //			 check(candidate_hash2==hash_stage2)
3961:                // Passwords can be 16 chars long
3962:                if (packet == null) {
3963:                    packet = new Buffer(packLength);
3964:                }
3965:
3966:                if (writeClientParams) {
3967:                    if (this .use41Extensions) {
3968:                        if (versionMeetsMinimum(4, 1, 1)) {
3969:                            packet.writeLong(this .clientParam);
3970:                            packet.writeLong(this .maxThreeBytes);
3971:
3972:                            // charset, JDBC will connect as 'utf8',
3973:                            // and use 'SET NAMES' to change to the desired
3974:                            // charset after the connection is established.
3975:                            packet.writeByte((byte) UTF8_CHARSET_INDEX);
3976:
3977:                            // Set of bytes reserved for future use.
3978:                            packet.writeBytesNoNull(new byte[23]);
3979:                        } else {
3980:                            packet.writeLong(this .clientParam);
3981:                            packet.writeLong(this .maxThreeBytes);
3982:                        }
3983:                    } else {
3984:                        packet.writeInt((int) this .clientParam);
3985:                        packet.writeLongInt(this .maxThreeBytes);
3986:                    }
3987:                }
3988:
3989:                // User/Password data
3990:                packet.writeString(user, "utf-8", this .connection);
3991:
3992:                if (password.length() != 0) {
3993:                    packet.writeByte((byte) 0x14);
3994:
3995:                    try {
3996:                        packet.writeBytesNoNull(Security.scramble411(password,
3997:                                this .seed));
3998:                    } catch (NoSuchAlgorithmException nse) {
3999:                        throw SQLError.createSQLException(Messages
4000:                                .getString("MysqlIO.95") //$NON-NLS-1$
4001:                                + Messages.getString("MysqlIO.96"), //$NON-NLS-1$
4002:                                SQLError.SQL_STATE_GENERAL_ERROR);
4003:                    }
4004:                } else {
4005:                    /* For empty password*/
4006:                    packet.writeByte((byte) 0);
4007:                }
4008:
4009:                if (this .useConnectWithDb) {
4010:                    packet.writeString(database, "utf-8", this .connection);
4011:                }
4012:
4013:                send(packet, packet.getPosition());
4014:
4015:                byte savePacketSequence = this .packetSequence++;
4016:
4017:                Buffer reply = checkErrorPacket();
4018:
4019:                if (reply.isLastDataPacket()) {
4020:                    /*
4021:                          By sending this very specific reply server asks us to send scrambled
4022:                          password in old format. The reply contains scramble_323.
4023:                     */
4024:                    this .packetSequence = ++savePacketSequence;
4025:                    packet.clear();
4026:
4027:                    String seed323 = this .seed.substring(0, 8);
4028:                    packet.writeString(Util.newCrypt(password, seed323));
4029:                    send(packet, packet.getPosition());
4030:
4031:                    /* Read what server thinks about out new auth message report */
4032:                    checkErrorPacket();
4033:                }
4034:            }
4035:
4036:            /**
4037:             * Un-packs binary-encoded result set data for one row
4038:             *
4039:             * @param fields
4040:             * @param binaryData
4041:             * @param resultSetConcurrency DOCUMENT ME!
4042:             *
4043:             * @return byte[][]
4044:             *
4045:             * @throws SQLException DOCUMENT ME!
4046:             */
4047:            private final ResultSetRow unpackBinaryResultSetRow(Field[] fields,
4048:                    Buffer binaryData, int resultSetConcurrency)
4049:                    throws SQLException {
4050:                int numFields = fields.length;
4051:
4052:                byte[][] unpackedRowData = new byte[numFields][];
4053:
4054:                //
4055:                // Unpack the null bitmask, first
4056:                //
4057:
4058:                /* Reserve place for null-marker bytes */
4059:                int nullCount = (numFields + 9) / 8;
4060:
4061:                byte[] nullBitMask = new byte[nullCount];
4062:
4063:                for (int i = 0; i < nullCount; i++) {
4064:                    nullBitMask[i] = binaryData.readByte();
4065:                }
4066:
4067:                int nullMaskPos = 0;
4068:                int bit = 4; // first two bits are reserved for future use
4069:
4070:                //
4071:                // TODO: Benchmark if moving check for updatable result
4072:                //       sets out of loop is worthwhile?
4073:                //
4074:
4075:                for (int i = 0; i < numFields; i++) {
4076:                    if ((nullBitMask[nullMaskPos] & bit) != 0) {
4077:                        unpackedRowData[i] = null;
4078:                    } else {
4079:                        if (resultSetConcurrency != ResultSetInternalMethods.CONCUR_UPDATABLE) {
4080:                            extractNativeEncodedColumn(binaryData, fields, i,
4081:                                    unpackedRowData);
4082:                        } else {
4083:                            unpackNativeEncodedColumn(binaryData, fields, i,
4084:                                    unpackedRowData);
4085:                        }
4086:                    }
4087:
4088:                    if (((bit <<= 1) & 255) == 0) {
4089:                        bit = 1; /* To next byte */
4090:
4091:                        nullMaskPos++;
4092:                    }
4093:                }
4094:
4095:                return new ByteArrayRow(unpackedRowData);
4096:            }
4097:
4098:            private final void extractNativeEncodedColumn(Buffer binaryData,
4099:                    Field[] fields, int columnIndex, byte[][] unpackedRowData)
4100:                    throws SQLException {
4101:                Field curField = fields[columnIndex];
4102:
4103:                switch (curField.getMysqlType()) {
4104:                case MysqlDefs.FIELD_TYPE_NULL:
4105:                    break; // for dummy binds
4106:
4107:                case MysqlDefs.FIELD_TYPE_TINY:
4108:
4109:                    unpackedRowData[columnIndex] = new byte[] { binaryData
4110:                            .readByte() };
4111:                    break;
4112:
4113:                case MysqlDefs.FIELD_TYPE_SHORT:
4114:                case MysqlDefs.FIELD_TYPE_YEAR:
4115:
4116:                    unpackedRowData[columnIndex] = binaryData.getBytes(2);
4117:                    break;
4118:                case MysqlDefs.FIELD_TYPE_LONG:
4119:                case MysqlDefs.FIELD_TYPE_INT24:
4120:
4121:                    unpackedRowData[columnIndex] = binaryData.getBytes(4);
4122:                    break;
4123:                case MysqlDefs.FIELD_TYPE_LONGLONG:
4124:
4125:                    unpackedRowData[columnIndex] = binaryData.getBytes(8);
4126:                    break;
4127:                case MysqlDefs.FIELD_TYPE_FLOAT:
4128:
4129:                    unpackedRowData[columnIndex] = binaryData.getBytes(4);
4130:                    break;
4131:                case MysqlDefs.FIELD_TYPE_DOUBLE:
4132:
4133:                    unpackedRowData[columnIndex] = binaryData.getBytes(8);
4134:                    break;
4135:                case MysqlDefs.FIELD_TYPE_TIME:
4136:
4137:                    int length = (int) binaryData.readFieldLength();
4138:
4139:                    unpackedRowData[columnIndex] = binaryData.getBytes(length);
4140:
4141:                    break;
4142:                case MysqlDefs.FIELD_TYPE_DATE:
4143:
4144:                    length = (int) binaryData.readFieldLength();
4145:
4146:                    unpackedRowData[columnIndex] = binaryData.getBytes(length);
4147:
4148:                    break;
4149:                case MysqlDefs.FIELD_TYPE_DATETIME:
4150:                case MysqlDefs.FIELD_TYPE_TIMESTAMP:
4151:                    length = (int) binaryData.readFieldLength();
4152:
4153:                    unpackedRowData[columnIndex] = binaryData.getBytes(length);
4154:                    break;
4155:                case MysqlDefs.FIELD_TYPE_TINY_BLOB:
4156:                case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
4157:                case MysqlDefs.FIELD_TYPE_LONG_BLOB:
4158:                case MysqlDefs.FIELD_TYPE_BLOB:
4159:                case MysqlDefs.FIELD_TYPE_VAR_STRING:
4160:                case MysqlDefs.FIELD_TYPE_VARCHAR:
4161:                case MysqlDefs.FIELD_TYPE_STRING:
4162:                case MysqlDefs.FIELD_TYPE_DECIMAL:
4163:                case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
4164:                case MysqlDefs.FIELD_TYPE_GEOMETRY:
4165:                    unpackedRowData[columnIndex] = binaryData
4166:                            .readLenByteArray(0);
4167:
4168:                    break;
4169:                case MysqlDefs.FIELD_TYPE_BIT:
4170:                    unpackedRowData[columnIndex] = binaryData
4171:                            .readLenByteArray(0);
4172:
4173:                    break;
4174:                default:
4175:                    throw SQLError.createSQLException(
4176:                            Messages.getString("MysqlIO.97") //$NON-NLS-1$
4177:                                    + curField.getMysqlType()
4178:                                    + Messages.getString("MysqlIO.98")
4179:                                    + columnIndex
4180:                                    + Messages.getString("MysqlIO.99") //$NON-NLS-1$ //$NON-NLS-2$
4181:                                    + fields.length
4182:                                    + Messages.getString("MysqlIO.100"), //$NON-NLS-1$
4183:                            SQLError.SQL_STATE_GENERAL_ERROR);
4184:                }
4185:            }
4186:
4187:            private final void unpackNativeEncodedColumn(Buffer binaryData,
4188:                    Field[] fields, int columnIndex, byte[][] unpackedRowData)
4189:                    throws SQLException {
4190:                Field curField = fields[columnIndex];
4191:
4192:                switch (curField.getMysqlType()) {
4193:                case MysqlDefs.FIELD_TYPE_NULL:
4194:                    break; // for dummy binds
4195:
4196:                case MysqlDefs.FIELD_TYPE_TINY:
4197:
4198:                    byte tinyVal = binaryData.readByte();
4199:
4200:                    if (!curField.isUnsigned()) {
4201:                        unpackedRowData[columnIndex] = String.valueOf(tinyVal)
4202:                                .getBytes();
4203:                    } else {
4204:                        short unsignedTinyVal = (short) (tinyVal & 0xff);
4205:
4206:                        unpackedRowData[columnIndex] = String.valueOf(
4207:                                unsignedTinyVal).getBytes();
4208:                    }
4209:
4210:                    break;
4211:
4212:                case MysqlDefs.FIELD_TYPE_SHORT:
4213:                case MysqlDefs.FIELD_TYPE_YEAR:
4214:
4215:                    short shortVal = (short) binaryData.readInt();
4216:
4217:                    if (!curField.isUnsigned()) {
4218:                        unpackedRowData[columnIndex] = String.valueOf(shortVal)
4219:                                .getBytes();
4220:                    } else {
4221:                        int unsignedShortVal = shortVal & 0xffff;
4222:
4223:                        unpackedRowData[columnIndex] = String.valueOf(
4224:                                unsignedShortVal).getBytes();
4225:                    }
4226:
4227:                    break;
4228:
4229:                case MysqlDefs.FIELD_TYPE_LONG:
4230:                case MysqlDefs.FIELD_TYPE_INT24:
4231:
4232:                    int intVal = (int) binaryData.readLong();
4233:
4234:                    if (!curField.isUnsigned()) {
4235:                        unpackedRowData[columnIndex] = String.valueOf(intVal)
4236:                                .getBytes();
4237:                    } else {
4238:                        long longVal = intVal & 0xffffffffL;
4239:
4240:                        unpackedRowData[columnIndex] = String.valueOf(longVal)
4241:                                .getBytes();
4242:                    }
4243:
4244:                    break;
4245:
4246:                case MysqlDefs.FIELD_TYPE_LONGLONG:
4247:
4248:                    long longVal = binaryData.readLongLong();
4249:
4250:                    if (!curField.isUnsigned()) {
4251:                        unpackedRowData[columnIndex] = String.valueOf(longVal)
4252:                                .getBytes();
4253:                    } else {
4254:                        BigInteger asBigInteger = ResultSetImpl
4255:                                .convertLongToUlong(longVal);
4256:
4257:                        unpackedRowData[columnIndex] = asBigInteger.toString()
4258:                                .getBytes();
4259:                    }
4260:
4261:                    break;
4262:
4263:                case MysqlDefs.FIELD_TYPE_FLOAT:
4264:
4265:                    float floatVal = Float.intBitsToFloat(binaryData
4266:                            .readIntAsLong());
4267:
4268:                    unpackedRowData[columnIndex] = String.valueOf(floatVal)
4269:                            .getBytes();
4270:
4271:                    break;
4272:
4273:                case MysqlDefs.FIELD_TYPE_DOUBLE:
4274:
4275:                    double doubleVal = Double.longBitsToDouble(binaryData
4276:                            .readLongLong());
4277:
4278:                    unpackedRowData[columnIndex] = String.valueOf(doubleVal)
4279:                            .getBytes();
4280:
4281:                    break;
4282:
4283:                case MysqlDefs.FIELD_TYPE_TIME:
4284:
4285:                    int length = (int) binaryData.readFieldLength();
4286:
4287:                    int hour = 0;
4288:                    int minute = 0;
4289:                    int seconds = 0;
4290:
4291:                    if (length != 0) {
4292:                        binaryData.readByte(); // skip tm->neg
4293:                        binaryData.readLong(); // skip daysPart
4294:                        hour = binaryData.readByte();
4295:                        minute = binaryData.readByte();
4296:                        seconds = binaryData.readByte();
4297:
4298:                        if (length > 8) {
4299:                            binaryData.readLong(); // ignore 'secondsPart'
4300:                        }
4301:                    }
4302:
4303:                    byte[] timeAsBytes = new byte[8];
4304:
4305:                    timeAsBytes[0] = (byte) Character.forDigit(hour / 10, 10);
4306:                    timeAsBytes[1] = (byte) Character.forDigit(hour % 10, 10);
4307:
4308:                    timeAsBytes[2] = (byte) ':';
4309:
4310:                    timeAsBytes[3] = (byte) Character.forDigit(minute / 10, 10);
4311:                    timeAsBytes[4] = (byte) Character.forDigit(minute % 10, 10);
4312:
4313:                    timeAsBytes[5] = (byte) ':';
4314:
4315:                    timeAsBytes[6] = (byte) Character
4316:                            .forDigit(seconds / 10, 10);
4317:                    timeAsBytes[7] = (byte) Character
4318:                            .forDigit(seconds % 10, 10);
4319:
4320:                    unpackedRowData[columnIndex] = timeAsBytes;
4321:
4322:                    break;
4323:
4324:                case MysqlDefs.FIELD_TYPE_DATE:
4325:                    length = (int) binaryData.readFieldLength();
4326:
4327:                    int year = 0;
4328:                    int month = 0;
4329:                    int day = 0;
4330:
4331:                    hour = 0;
4332:                    minute = 0;
4333:                    seconds = 0;
4334:
4335:                    if (length != 0) {
4336:                        year = binaryData.readInt();
4337:                        month = binaryData.readByte();
4338:                        day = binaryData.readByte();
4339:                    }
4340:
4341:                    if ((year == 0) && (month == 0) && (day == 0)) {
4342:                        if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL
4343:                                .equals(this .connection
4344:                                        .getZeroDateTimeBehavior())) {
4345:                            unpackedRowData[columnIndex] = null;
4346:
4347:                            break;
4348:                        } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION
4349:                                .equals(this .connection
4350:                                        .getZeroDateTimeBehavior())) {
4351:                            throw SQLError
4352:                                    .createSQLException(
4353:                                            "Value '0000-00-00' can not be represented as java.sql.Date",
4354:                                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4355:                        }
4356:
4357:                        year = 1;
4358:                        month = 1;
4359:                        day = 1;
4360:                    }
4361:
4362:                    byte[] dateAsBytes = new byte[10];
4363:
4364:                    dateAsBytes[0] = (byte) Character.forDigit(year / 1000, 10);
4365:
4366:                    int after1000 = year % 1000;
4367:
4368:                    dateAsBytes[1] = (byte) Character.forDigit(after1000 / 100,
4369:                            10);
4370:
4371:                    int after100 = after1000 % 100;
4372:
4373:                    dateAsBytes[2] = (byte) Character.forDigit(after100 / 10,
4374:                            10);
4375:                    dateAsBytes[3] = (byte) Character.forDigit(after100 % 10,
4376:                            10);
4377:
4378:                    dateAsBytes[4] = (byte) '-';
4379:
4380:                    dateAsBytes[5] = (byte) Character.forDigit(month / 10, 10);
4381:                    dateAsBytes[6] = (byte) Character.forDigit(month % 10, 10);
4382:
4383:                    dateAsBytes[7] = (byte) '-';
4384:
4385:                    dateAsBytes[8] = (byte) Character.forDigit(day / 10, 10);
4386:                    dateAsBytes[9] = (byte) Character.forDigit(day % 10, 10);
4387:
4388:                    unpackedRowData[columnIndex] = dateAsBytes;
4389:
4390:                    break;
4391:
4392:                case MysqlDefs.FIELD_TYPE_DATETIME:
4393:                case MysqlDefs.FIELD_TYPE_TIMESTAMP:
4394:                    length = (int) binaryData.readFieldLength();
4395:
4396:                    year = 0;
4397:                    month = 0;
4398:                    day = 0;
4399:
4400:                    hour = 0;
4401:                    minute = 0;
4402:                    seconds = 0;
4403:
4404:                    int nanos = 0;
4405:
4406:                    if (length != 0) {
4407:                        year = binaryData.readInt();
4408:                        month = binaryData.readByte();
4409:                        day = binaryData.readByte();
4410:
4411:                        if (length > 4) {
4412:                            hour = binaryData.readByte();
4413:                            minute = binaryData.readByte();
4414:                            seconds = binaryData.readByte();
4415:                        }
4416:
4417:                        //if (length > 7) {
4418:                        //    nanos = (int)binaryData.readLong();
4419:                        //}
4420:                    }
4421:
4422:                    if ((year == 0) && (month == 0) && (day == 0)) {
4423:                        if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL
4424:                                .equals(this .connection
4425:                                        .getZeroDateTimeBehavior())) {
4426:                            unpackedRowData[columnIndex] = null;
4427:
4428:                            break;
4429:                        } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION
4430:                                .equals(this .connection
4431:                                        .getZeroDateTimeBehavior())) {
4432:                            throw SQLError
4433:                                    .createSQLException(
4434:                                            "Value '0000-00-00' can not be represented as java.sql.Timestamp",
4435:                                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4436:                        }
4437:
4438:                        year = 1;
4439:                        month = 1;
4440:                        day = 1;
4441:                    }
4442:
4443:                    int stringLength = 19;
4444:
4445:                    byte[] nanosAsBytes = Integer.toString(nanos).getBytes();
4446:
4447:                    stringLength += (1 + nanosAsBytes.length); // '.' + # of digits
4448:
4449:                    byte[] datetimeAsBytes = new byte[stringLength];
4450:
4451:                    datetimeAsBytes[0] = (byte) Character.forDigit(year / 1000,
4452:                            10);
4453:
4454:                    after1000 = year % 1000;
4455:
4456:                    datetimeAsBytes[1] = (byte) Character.forDigit(
4457:                            after1000 / 100, 10);
4458:
4459:                    after100 = after1000 % 100;
4460:
4461:                    datetimeAsBytes[2] = (byte) Character.forDigit(
4462:                            after100 / 10, 10);
4463:                    datetimeAsBytes[3] = (byte) Character.forDigit(
4464:                            after100 % 10, 10);
4465:
4466:                    datetimeAsBytes[4] = (byte) '-';
4467:
4468:                    datetimeAsBytes[5] = (byte) Character.forDigit(month / 10,
4469:                            10);
4470:                    datetimeAsBytes[6] = (byte) Character.forDigit(month % 10,
4471:                            10);
4472:
4473:                    datetimeAsBytes[7] = (byte) '-';
4474:
4475:                    datetimeAsBytes[8] = (byte) Character
4476:                            .forDigit(day / 10, 10);
4477:                    datetimeAsBytes[9] = (byte) Character
4478:                            .forDigit(day % 10, 10);
4479:
4480:                    datetimeAsBytes[10] = (byte) ' ';
4481:
4482:                    datetimeAsBytes[11] = (byte) Character.forDigit(hour / 10,
4483:                            10);
4484:                    datetimeAsBytes[12] = (byte) Character.forDigit(hour % 10,
4485:                            10);
4486:
4487:                    datetimeAsBytes[13] = (byte) ':';
4488:
4489:                    datetimeAsBytes[14] = (byte) Character.forDigit(
4490:                            minute / 10, 10);
4491:                    datetimeAsBytes[15] = (byte) Character.forDigit(
4492:                            minute % 10, 10);
4493:
4494:                    datetimeAsBytes[16] = (byte) ':';
4495:
4496:                    datetimeAsBytes[17] = (byte) Character.forDigit(
4497:                            seconds / 10, 10);
4498:                    datetimeAsBytes[18] = (byte) Character.forDigit(
4499:                            seconds % 10, 10);
4500:
4501:                    datetimeAsBytes[19] = (byte) '.';
4502:
4503:                    int nanosOffset = 20;
4504:
4505:                    for (int j = 0; j < nanosAsBytes.length; j++) {
4506:                        datetimeAsBytes[nanosOffset + j] = nanosAsBytes[j];
4507:                    }
4508:
4509:                    unpackedRowData[columnIndex] = datetimeAsBytes;
4510:
4511:                    break;
4512:
4513:                case MysqlDefs.FIELD_TYPE_TINY_BLOB:
4514:                case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
4515:                case MysqlDefs.FIELD_TYPE_LONG_BLOB:
4516:                case MysqlDefs.FIELD_TYPE_BLOB:
4517:                case MysqlDefs.FIELD_TYPE_VAR_STRING:
4518:                case MysqlDefs.FIELD_TYPE_STRING:
4519:                case MysqlDefs.FIELD_TYPE_VARCHAR:
4520:                case MysqlDefs.FIELD_TYPE_DECIMAL:
4521:                case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
4522:                case MysqlDefs.FIELD_TYPE_BIT:
4523:                    unpackedRowData[columnIndex] = binaryData
4524:                            .readLenByteArray(0);
4525:
4526:                    break;
4527:
4528:                default:
4529:                    throw SQLError.createSQLException(
4530:                            Messages.getString("MysqlIO.97") //$NON-NLS-1$
4531:                                    + curField.getMysqlType()
4532:                                    + Messages.getString("MysqlIO.98")
4533:                                    + columnIndex
4534:                                    + Messages.getString("MysqlIO.99") //$NON-NLS-1$ //$NON-NLS-2$
4535:                                    + fields.length
4536:                                    + Messages.getString("MysqlIO.100"), //$NON-NLS-1$
4537:                            SQLError.SQL_STATE_GENERAL_ERROR);
4538:                }
4539:            }
4540:
4541:            /**
4542:             * Negotiates the SSL communications channel used when connecting
4543:             * to a MySQL server that understands SSL.
4544:             *
4545:             * @param user
4546:             * @param password
4547:             * @param database
4548:             * @param packLength
4549:             * @throws SQLException
4550:             * @throws CommunicationsException
4551:             */
4552:            private void negotiateSSLConnection(String user, String password,
4553:                    String database, int packLength) throws SQLException {
4554:                if (!ExportControlled.enabled()) {
4555:                    throw new ConnectionFeatureNotAvailableException(
4556:                            this .connection, this .lastPacketSentTimeMs, null);
4557:                }
4558:
4559:                boolean doSecureAuth = false;
4560:
4561:                if ((this .serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
4562:                    this .clientParam |= CLIENT_SECURE_CONNECTION;
4563:                    doSecureAuth = true;
4564:                }
4565:
4566:                this .clientParam |= CLIENT_SSL;
4567:
4568:                Buffer packet = new Buffer(packLength);
4569:
4570:                if (this .use41Extensions) {
4571:                    packet.writeLong(this .clientParam);
4572:                } else {
4573:                    packet.writeInt((int) this .clientParam);
4574:                }
4575:
4576:                send(packet, packet.getPosition());
4577:
4578:                ExportControlled.transformSocketToSSLSocket(this );
4579:
4580:                packet.clear();
4581:
4582:                if (doSecureAuth) {
4583:                    if (versionMeetsMinimum(4, 1, 1)) {
4584:                        secureAuth411(null, packLength, user, password,
4585:                                database, true);
4586:                    } else {
4587:                        secureAuth411(null, packLength, user, password,
4588:                                database, true);
4589:                    }
4590:                } else {
4591:                    if (this .use41Extensions) {
4592:                        packet.writeLong(this .clientParam);
4593:                        packet.writeLong(this .maxThreeBytes);
4594:                    } else {
4595:                        packet.writeInt((int) this .clientParam);
4596:                        packet.writeLongInt(this .maxThreeBytes);
4597:                    }
4598:
4599:                    // User/Password data
4600:                    packet.writeString(user);
4601:
4602:                    if (this .protocolVersion > 9) {
4603:                        packet.writeString(Util.newCrypt(password, this .seed));
4604:                    } else {
4605:                        packet.writeString(Util.oldCrypt(password, this .seed));
4606:                    }
4607:
4608:                    if (((this .serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0)
4609:                            && (database != null) && (database.length() > 0)) {
4610:                        packet.writeString(database);
4611:                    }
4612:
4613:                    send(packet, packet.getPosition());
4614:                }
4615:            }
4616:
4617:            protected int getServerStatus() {
4618:                return this .serverStatus;
4619:            }
4620:
4621:            protected List fetchRowsViaCursor(List fetchedRows,
4622:                    long statementId, Field[] columnTypes, int fetchSize,
4623:                    boolean useBufferRowExplicit) throws SQLException {
4624:
4625:                if (fetchedRows == null) {
4626:                    fetchedRows = new ArrayList(fetchSize);
4627:                } else {
4628:                    fetchedRows.clear();
4629:                }
4630:
4631:                this .sharedSendPacket.clear();
4632:
4633:                this .sharedSendPacket.writeByte((byte) MysqlDefs.COM_FETCH);
4634:                this .sharedSendPacket.writeLong(statementId);
4635:                this .sharedSendPacket.writeLong(fetchSize);
4636:
4637:                sendCommand(MysqlDefs.COM_FETCH, null, this .sharedSendPacket,
4638:                        true, null);
4639:
4640:                ResultSetRow row = null;
4641:
4642:                while ((row = nextRow(columnTypes, columnTypes.length, true,
4643:                        ResultSet.CONCUR_READ_ONLY, false,
4644:                        useBufferRowExplicit, false, null)) != null) {
4645:                    fetchedRows.add(row);
4646:                }
4647:
4648:                return fetchedRows;
4649:            }
4650:
4651:            protected long getThreadId() {
4652:                return this .threadId;
4653:            }
4654:
4655:            protected boolean useNanosForElapsedTime() {
4656:                return this .useNanosForElapsedTime;
4657:            }
4658:
4659:            protected long getSlowQueryThreshold() {
4660:                return this .slowQueryThreshold;
4661:            }
4662:
4663:            protected String getQueryTimingUnits() {
4664:                return this.queryTimingUnits;
4665:            }
4666:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.