Source Code Cross Referenced for ConnectionImpl.java in  » Database-JDBC-Connection-Pool » mysql » 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 » 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.IOException;
0028:        import java.io.UnsupportedEncodingException;
0029:        import java.lang.reflect.Array;
0030:        import java.lang.reflect.Constructor;
0031:        import java.lang.reflect.Method;
0032:        import java.sql.Blob;
0033:        import java.sql.DatabaseMetaData;
0034:        import java.sql.SQLException;
0035:        import java.sql.SQLWarning;
0036:        import java.sql.Savepoint;
0037:        import java.util.ArrayList;
0038:        import java.util.Calendar;
0039:        import java.util.GregorianCalendar;
0040:        import java.util.HashMap;
0041:        import java.util.Iterator;
0042:        import java.util.List;
0043:        import java.util.Locale;
0044:        import java.util.Map;
0045:        import java.util.Properties;
0046:        import java.util.Stack;
0047:        import java.util.StringTokenizer;
0048:        import java.util.TimeZone;
0049:        import java.util.Timer;
0050:        import java.util.TreeMap;
0051:
0052:        import com.mysql.jdbc.log.Log;
0053:        import com.mysql.jdbc.log.LogFactory;
0054:        import com.mysql.jdbc.log.NullLogger;
0055:        import com.mysql.jdbc.profiler.ProfileEventSink;
0056:        import com.mysql.jdbc.profiler.ProfilerEvent;
0057:        import com.mysql.jdbc.util.LRUCache;
0058:
0059:        /**
0060:         * A Connection represents a session with a specific database. Within the
0061:         * context of a Connection, SQL statements are executed and results are
0062:         * returned.
0063:         * <P>
0064:         * A Connection's database is able to provide information describing its tables,
0065:         * its supported SQL grammar, its stored procedures, the capabilities of this
0066:         * connection, etc. This information is obtained with the getMetaData method.
0067:         * </p>
0068:         * 
0069:         * @author Mark Matthews
0070:         * @version $Id: ConnectionImpl.java 6562 2007-09-05 16:02:17Z mmatthews $
0071:         * @see java.sql.Connection
0072:         */
0073:        public class ConnectionImpl extends ConnectionPropertiesImpl implements 
0074:                Connection {
0075:            private static final String JDBC_LOCAL_CHARACTER_SET_RESULTS = "jdbc.local.character_set_results";
0076:
0077:            /**
0078:             * Used as a key for caching callable statements which (may) depend on
0079:             * current catalog...In 5.0.x, they don't (currently), but stored procedure
0080:             * names soon will, so current catalog is a (hidden) component of the name.
0081:             */
0082:            class CompoundCacheKey {
0083:                String componentOne;
0084:
0085:                String componentTwo;
0086:
0087:                int hashCode;
0088:
0089:                CompoundCacheKey(String partOne, String partTwo) {
0090:                    this .componentOne = partOne;
0091:                    this .componentTwo = partTwo;
0092:
0093:                    // Handle first component (in most cases, currentCatalog)
0094:                    // being NULL....
0095:                    this .hashCode = (((this .componentOne != null) ? this .componentOne
0096:                            : "") + this .componentTwo).hashCode();
0097:                }
0098:
0099:                /*
0100:                 * (non-Javadoc)
0101:                 * 
0102:                 * @see java.lang.Object#equals(java.lang.Object)
0103:                 */
0104:                public boolean equals(Object obj) {
0105:                    if (obj instanceof  CompoundCacheKey) {
0106:                        CompoundCacheKey another = (CompoundCacheKey) obj;
0107:
0108:                        boolean firstPartEqual = false;
0109:
0110:                        if (this .componentOne == null) {
0111:                            firstPartEqual = (another.componentOne == null);
0112:                        } else {
0113:                            firstPartEqual = this .componentOne
0114:                                    .equals(another.componentOne);
0115:                        }
0116:
0117:                        return (firstPartEqual && this .componentTwo
0118:                                .equals(another.componentTwo));
0119:                    }
0120:
0121:                    return false;
0122:                }
0123:
0124:                /*
0125:                 * (non-Javadoc)
0126:                 * 
0127:                 * @see java.lang.Object#hashCode()
0128:                 */
0129:                public int hashCode() {
0130:                    return this .hashCode;
0131:                }
0132:            }
0133:
0134:            /**
0135:             * Marker for character set converter not being available (not written,
0136:             * multibyte, etc) Used to prevent multiple instantiation requests.
0137:             */
0138:            private static final Object CHARSET_CONVERTER_NOT_AVAILABLE_MARKER = new Object();
0139:
0140:            /**
0141:             * The mapping between MySQL charset names and Java charset names.
0142:             * Initialized by loadCharacterSetMapping()
0143:             */
0144:            public static Map charsetMap;
0145:
0146:            /** Default logger class name */
0147:            protected static final String DEFAULT_LOGGER_CLASS = "com.mysql.jdbc.log.StandardLogger";
0148:
0149:            private final static int HISTOGRAM_BUCKETS = 20;
0150:
0151:            /** Logger instance name */
0152:            private static final String LOGGER_INSTANCE_NAME = "MySQL";
0153:
0154:            /**
0155:             * Map mysql transaction isolation level name to
0156:             * java.sql.Connection.TRANSACTION_XXX
0157:             */
0158:            private static Map mapTransIsolationNameToValue = null;
0159:
0160:            /** Null logger shared by all connections at startup */
0161:            private static final Log NULL_LOGGER = new NullLogger(
0162:                    LOGGER_INSTANCE_NAME);
0163:
0164:            private static Map roundRobinStatsMap;
0165:
0166:            private static final Map serverCollationByUrl = new HashMap();
0167:
0168:            private static final Map serverConfigByUrl = new HashMap();
0169:
0170:            private static Timer cancelTimer;
0171:            private static final Constructor JDBC_4_CONNECTION_CTOR;
0172:
0173:            static {
0174:                mapTransIsolationNameToValue = new HashMap(8);
0175:                mapTransIsolationNameToValue.put("READ-UNCOMMITED", Constants
0176:                        .integerValueOf(TRANSACTION_READ_UNCOMMITTED));
0177:                mapTransIsolationNameToValue.put("READ-UNCOMMITTED", Constants
0178:                        .integerValueOf(TRANSACTION_READ_UNCOMMITTED));
0179:                mapTransIsolationNameToValue.put("READ-COMMITTED", Constants
0180:                        .integerValueOf(TRANSACTION_READ_COMMITTED));
0181:                mapTransIsolationNameToValue.put("REPEATABLE-READ", Constants
0182:                        .integerValueOf(TRANSACTION_REPEATABLE_READ));
0183:                mapTransIsolationNameToValue.put("SERIALIZABLE", Constants
0184:                        .integerValueOf(TRANSACTION_SERIALIZABLE));
0185:
0186:                boolean createdNamedTimer = false;
0187:
0188:                // Use reflection magic to try this on JDK's 1.5 and newer, fallback to non-named
0189:                // timer on older VMs.
0190:                try {
0191:                    Constructor ctr = Timer.class.getConstructor(new Class[] {
0192:                            String.class, Boolean.TYPE });
0193:
0194:                    cancelTimer = (Timer) ctr
0195:                            .newInstance(new Object[] {
0196:                                    "MySQL Statement Cancellation Timer",
0197:                                    Boolean.TRUE });
0198:                    createdNamedTimer = true;
0199:                } catch (Throwable t) {
0200:                    createdNamedTimer = false;
0201:                }
0202:
0203:                if (!createdNamedTimer) {
0204:                    cancelTimer = new Timer(true);
0205:                }
0206:
0207:                if (Util.isJdbc4()) {
0208:                    try {
0209:                        JDBC_4_CONNECTION_CTOR = Class.forName(
0210:                                "com.mysql.jdbc.JDBC4Connection")
0211:                                .getConstructor(
0212:                                        new Class[] { String.class,
0213:                                                Integer.TYPE, Properties.class,
0214:                                                String.class, String.class });
0215:                    } catch (SecurityException e) {
0216:                        throw new RuntimeException(e);
0217:                    } catch (NoSuchMethodException e) {
0218:                        throw new RuntimeException(e);
0219:                    } catch (ClassNotFoundException e) {
0220:                        throw new RuntimeException(e);
0221:                    }
0222:                } else {
0223:                    JDBC_4_CONNECTION_CTOR = null;
0224:                }
0225:            }
0226:
0227:            protected static SQLException appendMessageToException(
0228:                    SQLException sqlEx, String messageToAppend) {
0229:                String origMessage = sqlEx.getMessage();
0230:                String sqlState = sqlEx.getSQLState();
0231:                int vendorErrorCode = sqlEx.getErrorCode();
0232:
0233:                StringBuffer messageBuf = new StringBuffer(origMessage.length()
0234:                        + messageToAppend.length());
0235:                messageBuf.append(origMessage);
0236:                messageBuf.append(messageToAppend);
0237:
0238:                SQLException sqlExceptionWithNewMessage = SQLError
0239:                        .createSQLException(messageBuf.toString(), sqlState,
0240:                                vendorErrorCode);
0241:
0242:                //
0243:                // Try and maintain the original stack trace,
0244:                // only works on JDK-1.4 and newer
0245:                //
0246:
0247:                try {
0248:                    // Have to do this with reflection, otherwise older JVMs croak
0249:                    Method getStackTraceMethod = null;
0250:                    Method setStackTraceMethod = null;
0251:                    Object theStackTraceAsObject = null;
0252:
0253:                    Class stackTraceElementClass = Class
0254:                            .forName("java.lang.StackTraceElement");
0255:                    Class stackTraceElementArrayClass = Array.newInstance(
0256:                            stackTraceElementClass, new int[] { 0 }).getClass();
0257:
0258:                    getStackTraceMethod = Throwable.class.getMethod(
0259:                            "getStackTrace", new Class[] {});
0260:
0261:                    setStackTraceMethod = Throwable.class.getMethod(
0262:                            "setStackTrace",
0263:                            new Class[] { stackTraceElementArrayClass });
0264:
0265:                    if (getStackTraceMethod != null
0266:                            && setStackTraceMethod != null) {
0267:                        theStackTraceAsObject = getStackTraceMethod.invoke(
0268:                                sqlEx, new Object[0]);
0269:                        setStackTraceMethod.invoke(sqlExceptionWithNewMessage,
0270:                                new Object[] { theStackTraceAsObject });
0271:                    }
0272:                } catch (NoClassDefFoundError noClassDefFound) {
0273:
0274:                } catch (NoSuchMethodException noSuchMethodEx) {
0275:
0276:                } catch (Throwable catchAll) {
0277:
0278:                }
0279:
0280:                return sqlExceptionWithNewMessage;
0281:            }
0282:
0283:            protected static Timer getCancelTimer() {
0284:                return cancelTimer;
0285:            }
0286:
0287:            /**
0288:             * Creates a connection instance -- We need to provide factory-style methods
0289:             * so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
0290:             * the class verifier complains when it tries to load JDBC4-only interface
0291:             * classes that are present in JDBC4 method signatures.
0292:             */
0293:
0294:            protected static Connection getInstance(String hostToConnectTo,
0295:                    int portToConnectTo, Properties info,
0296:                    String databaseToConnectTo, String url) throws SQLException {
0297:                if (!Util.isJdbc4()) {
0298:                    return new ConnectionImpl(hostToConnectTo, portToConnectTo,
0299:                            info, databaseToConnectTo, url);
0300:                }
0301:
0302:                return (Connection) Util.handleNewInstance(
0303:                        JDBC_4_CONNECTION_CTOR, new Object[] { hostToConnectTo,
0304:                                Constants.integerValueOf(portToConnectTo),
0305:                                info, databaseToConnectTo, url });
0306:            }
0307:
0308:            private static synchronized int getNextRoundRobinHostIndex(
0309:                    String url, List hostList) {
0310:                if (roundRobinStatsMap == null) {
0311:                    roundRobinStatsMap = new HashMap();
0312:                }
0313:
0314:                int[] index = (int[]) roundRobinStatsMap.get(url);
0315:
0316:                if (index == null) {
0317:                    index = new int[1];
0318:                    index[0] = -1;
0319:
0320:                    roundRobinStatsMap.put(url, index);
0321:                }
0322:
0323:                index[0]++;
0324:
0325:                if (index[0] >= hostList.size()) {
0326:                    index[0] = 0;
0327:                }
0328:
0329:                return index[0];
0330:            }
0331:
0332:            private static boolean nullSafeCompare(String s1, String s2) {
0333:                if (s1 == null && s2 == null) {
0334:                    return true;
0335:                }
0336:
0337:                if (s1 == null && s2 != null) {
0338:                    return false;
0339:                }
0340:
0341:                return s1.equals(s2);
0342:            }
0343:
0344:            /** Are we in autoCommit mode? */
0345:            private boolean autoCommit = true;
0346:
0347:            /** A map of SQL to parsed prepared statement parameters. */
0348:            private Map cachedPreparedStatementParams;
0349:
0350:            /**
0351:             * For servers > 4.1.0, what character set is the metadata returned in?
0352:             */
0353:            private String characterSetMetadata = null;
0354:
0355:            /**
0356:             * The character set we want results and result metadata returned in (null ==
0357:             * results in any charset, metadata in UTF-8).
0358:             */
0359:            private String characterSetResultsOnServer = null;
0360:
0361:            /**
0362:             * Holds cached mappings to charset converters to avoid static
0363:             * synchronization and at the same time save memory (each charset converter
0364:             * takes approx 65K of static data).
0365:             */
0366:            private Map charsetConverterMap = new HashMap(CharsetMapping
0367:                    .getNumberOfCharsetsConfigured());
0368:
0369:            /**
0370:             * The mapping between MySQL charset names and the max number of chars in
0371:             * them. Lazily instantiated via getMaxBytesPerChar().
0372:             */
0373:            private Map charsetToNumBytesMap;
0374:
0375:            /** The point in time when this connection was created */
0376:            private long connectionCreationTimeMillis = 0;
0377:
0378:            /** ID used when profiling */
0379:            private long connectionId;
0380:
0381:            /** The database we're currently using (called Catalog in JDBC terms). */
0382:            private String database = null;
0383:
0384:            /** Internal DBMD to use for various database-version specific features */
0385:            private DatabaseMetaData dbmd = null;
0386:
0387:            private TimeZone defaultTimeZone;
0388:
0389:            /** The event sink to use for profiling */
0390:            private ProfileEventSink eventSink;
0391:
0392:            private boolean executingFailoverReconnect = false;
0393:
0394:            /** Are we failed-over to a non-master host */
0395:            private boolean failedOver = false;
0396:
0397:            /** Why was this connection implicitly closed, if known? (for diagnostics) */
0398:            private Throwable forceClosedReason;
0399:
0400:            /** Where was this connection implicitly closed? (for diagnostics) */
0401:            private Throwable forcedClosedLocation;
0402:
0403:            /** Does the server suuport isolation levels? */
0404:            private boolean hasIsolationLevels = false;
0405:
0406:            /** Does this version of MySQL support quoted identifiers? */
0407:            private boolean hasQuotedIdentifiers = false;
0408:
0409:            /** The hostname we're connected to */
0410:            private String host = null;
0411:
0412:            /** The list of host(s) to try and connect to */
0413:            private List hostList = null;
0414:
0415:            /** How many hosts are in the host list? */
0416:            private int hostListSize = 0;
0417:
0418:            /**
0419:             * We need this 'bootstrapped', because 4.1 and newer will send fields back
0420:             * with this even before we fill this dynamically from the server.
0421:             */
0422:            private String[] indexToCharsetMapping = CharsetMapping.INDEX_TO_CHARSET;
0423:
0424:            /** The I/O abstraction interface (network conn to MySQL server */
0425:            private MysqlIO io = null;
0426:
0427:            private boolean isClientTzUTC = false;
0428:
0429:            /** Has this connection been closed? */
0430:            private boolean isClosed = true;
0431:
0432:            /** Is this connection associated with a global tx? */
0433:            private boolean isInGlobalTx = false;
0434:
0435:            /** Is this connection running inside a JDK-1.3 VM? */
0436:            private boolean isRunningOnJDK13 = false;
0437:
0438:            /** isolation level */
0439:            private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
0440:
0441:            private boolean isServerTzUTC = false;
0442:
0443:            /** When did the last query finish? */
0444:            private long lastQueryFinishedTime = 0;
0445:
0446:            /** The logger we're going to use */
0447:            private Log log = NULL_LOGGER;
0448:
0449:            /**
0450:             * If gathering metrics, what was the execution time of the longest query so
0451:             * far ?
0452:             */
0453:            private long longestQueryTimeMs = 0;
0454:
0455:            /** Is the server configured to use lower-case table names only? */
0456:            private boolean lowerCaseTableNames = false;
0457:
0458:            /** When did the master fail? */
0459:            private long masterFailTimeMillis = 0L;
0460:
0461:            /**
0462:             * The largest packet we can send (changed once we know what the server
0463:             * supports, we get this at connection init).
0464:             */
0465:            private int maxAllowedPacket = 65536;
0466:
0467:            private long maximumNumberTablesAccessed = 0;
0468:
0469:            /** Has the max-rows setting been changed from the default? */
0470:            private boolean maxRowsChanged = false;
0471:
0472:            /** When was the last time we reported metrics? */
0473:            private long metricsLastReportedMs;
0474:
0475:            private long minimumNumberTablesAccessed = Long.MAX_VALUE;
0476:
0477:            /** Mutex */
0478:            private final Object mutex = new Object();
0479:
0480:            /** The JDBC URL we're using */
0481:            private String myURL = null;
0482:
0483:            /** Does this connection need to be tested? */
0484:            private boolean needsPing = false;
0485:
0486:            private int netBufferLength = 16384;
0487:
0488:            private boolean noBackslashEscapes = false;
0489:
0490:            private long numberOfPreparedExecutes = 0;
0491:
0492:            private long numberOfPrepares = 0;
0493:
0494:            private long numberOfQueriesIssued = 0;
0495:
0496:            private long numberOfResultSetsCreated = 0;
0497:
0498:            private long[] numTablesMetricsHistBreakpoints;
0499:
0500:            private int[] numTablesMetricsHistCounts;
0501:
0502:            private long[] oldHistBreakpoints = null;
0503:
0504:            private int[] oldHistCounts = null;
0505:
0506:            /** A map of currently open statements */
0507:            private Map openStatements;
0508:
0509:            private LRUCache parsedCallableStatementCache;
0510:
0511:            private boolean parserKnowsUnicode = false;
0512:
0513:            /** The password we used */
0514:            private String password = null;
0515:
0516:            private long[] perfMetricsHistBreakpoints;
0517:
0518:            private int[] perfMetricsHistCounts;
0519:
0520:            /** Point of origin where this Connection was created */
0521:            private Throwable pointOfOrigin;
0522:
0523:            /** The port number we're connected to (defaults to 3306) */
0524:            private int port = 3306;
0525:
0526:            /**
0527:             * Used only when testing failover functionality for regressions, causes the
0528:             * failover code to not retry the master first
0529:             */
0530:            private boolean preferSlaveDuringFailover = false;
0531:
0532:            /** Properties for this connection specified by user */
0533:            protected Properties props = null;
0534:
0535:            /** Number of queries we've issued since the master failed */
0536:            private long queriesIssuedFailedOver = 0;
0537:
0538:            /** Should we retrieve 'info' messages from the server? */
0539:            private boolean readInfoMsg = false;
0540:
0541:            /** Are we in read-only mode? */
0542:            private boolean readOnly = false;
0543:
0544:            /** Cache of ResultSet metadata */
0545:            protected LRUCache resultSetMetadataCache;
0546:
0547:            /** The timezone of the server */
0548:            private TimeZone serverTimezoneTZ = null;
0549:
0550:            /** The map of server variables that we retrieve at connection init. */
0551:            private Map serverVariables = null;
0552:
0553:            private long shortestQueryTimeMs = Long.MAX_VALUE;
0554:
0555:            /** A map of statements that have had setMaxRows() called on them */
0556:            private Map statementsUsingMaxRows;
0557:
0558:            private double totalQueryTimeMs = 0;
0559:
0560:            /** Are transactions supported by the MySQL server we are connected to? */
0561:            private boolean transactionsSupported = false;
0562:
0563:            /**
0564:             * The type map for UDTs (not implemented, but used by some third-party
0565:             * vendors, most notably IBM WebSphere)
0566:             */
0567:            private Map typeMap;
0568:
0569:            /** Has ANSI_QUOTES been enabled on the server? */
0570:            private boolean useAnsiQuotes = false;
0571:
0572:            /** The user we're connected as */
0573:            private String user = null;
0574:
0575:            /**
0576:             * Should we use server-side prepared statements? (auto-detected, but can be
0577:             * disabled by user)
0578:             */
0579:            private boolean useServerPreparedStmts = false;
0580:
0581:            private LRUCache serverSideStatementCheckCache;
0582:            private LRUCache serverSideStatementCache;
0583:            private Calendar sessionCalendar;
0584:
0585:            private Calendar utcCalendar;
0586:
0587:            private String origHostToConnectTo;
0588:
0589:            // we don't want to be able to publicly clone this...
0590:
0591:            private int origPortToConnectTo;
0592:
0593:            private String origDatabaseToConnectTo;
0594:
0595:            private String errorMessageEncoding = "Cp1252"; // to begin with, changes after we talk to the server
0596:
0597:            private boolean usePlatformCharsetConverters;
0598:
0599:            /*
0600:             * For testing failover scenarios
0601:             */
0602:            private boolean hasTriedMasterFlag = false;
0603:
0604:            /**
0605:             * The comment (if any) that we'll prepend to all statements
0606:             * sent to the server (to show up in "SHOW PROCESSLIST")
0607:             */
0608:            private String statementComment = null;
0609:
0610:            /**'
0611:             * For the delegate only
0612:             */
0613:            protected ConnectionImpl() {
0614:            }
0615:
0616:            /**
0617:             * Creates a connection to a MySQL Server.
0618:             * 
0619:             * @param hostToConnectTo
0620:             *            the hostname of the database server
0621:             * @param portToConnectTo
0622:             *            the port number the server is listening on
0623:             * @param info
0624:             *            a Properties[] list holding the user and password
0625:             * @param databaseToConnectTo
0626:             *            the database to connect to
0627:             * @param url
0628:             *            the URL of the connection
0629:             * @param d
0630:             *            the Driver instantation of the connection
0631:             * @exception SQLException
0632:             *                if a database access error occurs
0633:             */
0634:            protected ConnectionImpl(String hostToConnectTo,
0635:                    int portToConnectTo, Properties info,
0636:                    String databaseToConnectTo, String url) throws SQLException {
0637:                this .charsetToNumBytesMap = new HashMap();
0638:
0639:                this .connectionCreationTimeMillis = System.currentTimeMillis();
0640:                this .pointOfOrigin = new Throwable();
0641:
0642:                // Stash away for later, used to clone this connection for Statement.cancel
0643:                // and Statement.setQueryTimeout().
0644:                //
0645:
0646:                this .origHostToConnectTo = hostToConnectTo;
0647:                this .origPortToConnectTo = portToConnectTo;
0648:                this .origDatabaseToConnectTo = databaseToConnectTo;
0649:
0650:                try {
0651:                    Blob.class.getMethod("truncate", new Class[] { Long.TYPE });
0652:
0653:                    this .isRunningOnJDK13 = false;
0654:                } catch (NoSuchMethodException nsme) {
0655:                    this .isRunningOnJDK13 = true;
0656:                }
0657:
0658:                this .sessionCalendar = new GregorianCalendar();
0659:                this .utcCalendar = new GregorianCalendar();
0660:                this .utcCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
0661:
0662:                //
0663:                // Normally, this code would be in initializeDriverProperties,
0664:                // but we need to do this as early as possible, so we can start
0665:                // logging to the 'correct' place as early as possible...this.log
0666:                // points to 'NullLogger' for every connection at startup to avoid
0667:                // NPEs and the overhead of checking for NULL at every logging call.
0668:                //
0669:                // We will reset this to the configured logger during properties
0670:                // initialization.
0671:                //
0672:                this .log = LogFactory.getLogger(getLogger(),
0673:                        LOGGER_INSTANCE_NAME);
0674:
0675:                // We store this per-connection, due to static synchronization
0676:                // issues in Java's built-in TimeZone class...
0677:                this .defaultTimeZone = Util.getDefaultTimeZone();
0678:
0679:                if ("GMT".equalsIgnoreCase(this .defaultTimeZone.getID())) {
0680:                    this .isClientTzUTC = true;
0681:                } else {
0682:                    this .isClientTzUTC = false;
0683:                }
0684:
0685:                this .openStatements = new HashMap();
0686:                this .serverVariables = new HashMap();
0687:                this .hostList = new ArrayList();
0688:
0689:                if (hostToConnectTo == null) {
0690:                    this .host = "localhost";
0691:                    this .hostList.add(this .host);
0692:                } else if (hostToConnectTo.indexOf(',') != -1) {
0693:                    // multiple hosts separated by commas (failover)
0694:                    StringTokenizer hostTokenizer = new StringTokenizer(
0695:                            hostToConnectTo, ",", false);
0696:
0697:                    while (hostTokenizer.hasMoreTokens()) {
0698:                        this .hostList.add(hostTokenizer.nextToken().trim());
0699:                    }
0700:                } else {
0701:                    this .host = hostToConnectTo;
0702:                    this .hostList.add(this .host);
0703:                }
0704:
0705:                this .hostListSize = this .hostList.size();
0706:                this .port = portToConnectTo;
0707:
0708:                if (databaseToConnectTo == null) {
0709:                    databaseToConnectTo = "";
0710:                }
0711:
0712:                this .database = databaseToConnectTo;
0713:                this .myURL = url;
0714:                this .user = info
0715:                        .getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);
0716:                this .password = info
0717:                        .getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
0718:
0719:                if ((this .user == null) || this .user.equals("")) {
0720:                    this .user = "";
0721:                }
0722:
0723:                if (this .password == null) {
0724:                    this .password = "";
0725:                }
0726:
0727:                this .props = info;
0728:                initializeDriverProperties(info);
0729:
0730:                try {
0731:                    createNewIO(false);
0732:                    this .dbmd = getMetaData();
0733:                } catch (SQLException ex) {
0734:                    cleanup(ex);
0735:
0736:                    // don't clobber SQL exceptions
0737:                    throw ex;
0738:                } catch (Exception ex) {
0739:                    cleanup(ex);
0740:
0741:                    StringBuffer mesg = new StringBuffer(128);
0742:
0743:                    if (getParanoid()) {
0744:                        mesg.append("Cannot connect to MySQL server on ");
0745:                        mesg.append(this .host);
0746:                        mesg.append(":");
0747:                        mesg.append(this .port);
0748:                        mesg.append(".\n\n");
0749:                        mesg.append("Make sure that there is a MySQL server ");
0750:                        mesg
0751:                                .append("running on the machine/port you are trying ");
0752:                        mesg
0753:                                .append("to connect to and that the machine this software is "
0754:                                        + "running on ");
0755:                        mesg.append("is able to connect to this host/port "
0756:                                + "(i.e. not firewalled). ");
0757:                        mesg
0758:                                .append("Also make sure that the server has not been started "
0759:                                        + "with the --skip-networking ");
0760:                        mesg.append("flag.\n\n");
0761:                    } else {
0762:                        mesg.append("Unable to connect to database.");
0763:                    }
0764:
0765:                    mesg.append("Underlying exception: \n\n");
0766:                    mesg.append(ex.getClass().getName());
0767:
0768:                    if (!getParanoid()) {
0769:                        mesg.append(Util.stackTraceToString(ex));
0770:                    }
0771:
0772:                    throw SQLError.createSQLException(mesg.toString(),
0773:                            SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE);
0774:                }
0775:            }
0776:
0777:            private void addToHistogram(int[] histogramCounts,
0778:                    long[] histogramBreakpoints, long value, int numberOfTimes,
0779:                    long currentLowerBound, long currentUpperBound) {
0780:                if (histogramCounts == null) {
0781:                    createInitialHistogram(histogramBreakpoints,
0782:                            currentLowerBound, currentUpperBound);
0783:                }
0784:
0785:                for (int i = 0; i < HISTOGRAM_BUCKETS; i++) {
0786:                    if (histogramBreakpoints[i] >= value) {
0787:                        histogramCounts[i] += numberOfTimes;
0788:
0789:                        break;
0790:                    }
0791:                }
0792:            }
0793:
0794:            private void addToPerformanceHistogram(long value, int numberOfTimes) {
0795:                checkAndCreatePerformanceHistogram();
0796:
0797:                addToHistogram(this .perfMetricsHistCounts,
0798:                        this .perfMetricsHistBreakpoints, value, numberOfTimes,
0799:                        this .shortestQueryTimeMs == Long.MAX_VALUE ? 0
0800:                                : this .shortestQueryTimeMs,
0801:                        this .longestQueryTimeMs);
0802:            }
0803:
0804:            private void addToTablesAccessedHistogram(long value,
0805:                    int numberOfTimes) {
0806:                checkAndCreateTablesAccessedHistogram();
0807:
0808:                addToHistogram(this .numTablesMetricsHistCounts,
0809:                        this .numTablesMetricsHistBreakpoints, value,
0810:                        numberOfTimes,
0811:                        this .minimumNumberTablesAccessed == Long.MAX_VALUE ? 0
0812:                                : this .minimumNumberTablesAccessed,
0813:                        this .maximumNumberTablesAccessed);
0814:            }
0815:
0816:            /**
0817:             * Builds the map needed for 4.1.0 and newer servers that maps field-level
0818:             * charset/collation info to a java character encoding name.
0819:             * 
0820:             * @throws SQLException
0821:             *             DOCUMENT ME!
0822:             */
0823:            private void buildCollationMapping() throws SQLException {
0824:                if (versionMeetsMinimum(4, 1, 0)) {
0825:
0826:                    TreeMap sortedCollationMap = null;
0827:
0828:                    if (getCacheServerConfiguration()) {
0829:                        synchronized (serverConfigByUrl) {
0830:                            sortedCollationMap = (TreeMap) serverCollationByUrl
0831:                                    .get(getURL());
0832:                        }
0833:                    }
0834:
0835:                    java.sql.Statement stmt = null;
0836:                    java.sql.ResultSet results = null;
0837:
0838:                    try {
0839:                        if (sortedCollationMap == null) {
0840:                            sortedCollationMap = new TreeMap();
0841:
0842:                            stmt = createStatement();
0843:
0844:                            if (stmt.getMaxRows() != 0) {
0845:                                stmt.setMaxRows(0);
0846:                            }
0847:
0848:                            results = stmt.executeQuery("SHOW COLLATION");
0849:
0850:                            while (results.next()) {
0851:                                String charsetName = results.getString(2);
0852:                                Integer charsetIndex = Constants
0853:                                        .integerValueOf(results.getInt(3));
0854:
0855:                                sortedCollationMap.put(charsetIndex,
0856:                                        charsetName);
0857:                            }
0858:
0859:                            if (getCacheServerConfiguration()) {
0860:                                synchronized (serverConfigByUrl) {
0861:                                    serverCollationByUrl.put(getURL(),
0862:                                            sortedCollationMap);
0863:                                }
0864:                            }
0865:
0866:                        }
0867:
0868:                        // Now, merge with what we already know
0869:                        int highestIndex = ((Integer) sortedCollationMap
0870:                                .lastKey()).intValue();
0871:
0872:                        if (CharsetMapping.INDEX_TO_CHARSET.length > highestIndex) {
0873:                            highestIndex = CharsetMapping.INDEX_TO_CHARSET.length;
0874:                        }
0875:
0876:                        this .indexToCharsetMapping = new String[highestIndex + 1];
0877:
0878:                        for (int i = 0; i < CharsetMapping.INDEX_TO_CHARSET.length; i++) {
0879:                            this .indexToCharsetMapping[i] = CharsetMapping.INDEX_TO_CHARSET[i];
0880:                        }
0881:
0882:                        for (Iterator indexIter = sortedCollationMap.entrySet()
0883:                                .iterator(); indexIter.hasNext();) {
0884:                            Map.Entry indexEntry = (Map.Entry) indexIter.next();
0885:
0886:                            String mysqlCharsetName = (String) indexEntry
0887:                                    .getValue();
0888:
0889:                            this .indexToCharsetMapping[((Integer) indexEntry
0890:                                    .getKey()).intValue()] = CharsetMapping
0891:                                    .getJavaEncodingForMysqlEncoding(
0892:                                            mysqlCharsetName, this );
0893:                        }
0894:                    } catch (java.sql.SQLException e) {
0895:                        throw e;
0896:                    } finally {
0897:                        if (results != null) {
0898:                            try {
0899:                                results.close();
0900:                            } catch (java.sql.SQLException sqlE) {
0901:                                // ignore
0902:                            }
0903:                        }
0904:
0905:                        if (stmt != null) {
0906:                            try {
0907:                                stmt.close();
0908:                            } catch (java.sql.SQLException sqlE) {
0909:                                // ignore
0910:                            }
0911:                        }
0912:                    }
0913:                } else {
0914:                    // Safety, we already do this as an initializer, but this makes
0915:                    // the intent more clear
0916:                    this .indexToCharsetMapping = CharsetMapping.INDEX_TO_CHARSET;
0917:                }
0918:            }
0919:
0920:            private boolean canHandleAsServerPreparedStatement(String sql)
0921:                    throws SQLException {
0922:                if (sql == null || sql.length() == 0) {
0923:                    return true;
0924:                }
0925:
0926:                if (getCachePreparedStatements()) {
0927:                    synchronized (this .serverSideStatementCheckCache) {
0928:                        Boolean flag = (Boolean) this .serverSideStatementCheckCache
0929:                                .get(sql);
0930:
0931:                        if (flag != null) {
0932:                            return flag.booleanValue();
0933:                        }
0934:
0935:                        boolean canHandle = canHandleAsServerPreparedStatementNoCache(sql);
0936:
0937:                        if (sql.length() < getPreparedStatementCacheSqlLimit()) {
0938:                            this .serverSideStatementCheckCache.put(sql,
0939:                                    canHandle ? Boolean.TRUE : Boolean.FALSE);
0940:                        }
0941:
0942:                        return canHandle;
0943:                    }
0944:                }
0945:
0946:                return canHandleAsServerPreparedStatementNoCache(sql);
0947:            }
0948:
0949:            private boolean canHandleAsServerPreparedStatementNoCache(String sql)
0950:                    throws SQLException {
0951:
0952:                // Can't use server-side prepare for CALL
0953:                if (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,
0954:                        "CALL")) {
0955:                    return false;
0956:                }
0957:
0958:                boolean canHandleAsStatement = true;
0959:
0960:                if (!versionMeetsMinimum(5, 0, 7)
0961:                        && (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(
0962:                                sql, "SELECT")
0963:                                || StringUtils
0964:                                        .startsWithIgnoreCaseAndNonAlphaNumeric(
0965:                                                sql, "DELETE")
0966:                                || StringUtils
0967:                                        .startsWithIgnoreCaseAndNonAlphaNumeric(
0968:                                                sql, "INSERT")
0969:                                || StringUtils
0970:                                        .startsWithIgnoreCaseAndNonAlphaNumeric(
0971:                                                sql, "UPDATE") || StringUtils
0972:                                .startsWithIgnoreCaseAndNonAlphaNumeric(sql,
0973:                                        "REPLACE"))) {
0974:
0975:                    // check for limit ?[,?]
0976:
0977:                    /*
0978:                     * The grammar for this (from the server) is: ULONG_NUM | ULONG_NUM
0979:                     * ',' ULONG_NUM | ULONG_NUM OFFSET_SYM ULONG_NUM
0980:                     */
0981:
0982:                    int currentPos = 0;
0983:                    int statementLength = sql.length();
0984:                    int lastPosToLook = statementLength - 7; // "LIMIT ".length()
0985:                    boolean allowBackslashEscapes = !this .noBackslashEscapes;
0986:                    char quoteChar = this .useAnsiQuotes ? '"' : '\'';
0987:                    boolean foundLimitWithPlaceholder = false;
0988:
0989:                    while (currentPos < lastPosToLook) {
0990:                        int limitStart = StringUtils
0991:                                .indexOfIgnoreCaseRespectQuotes(currentPos,
0992:                                        sql, "LIMIT ", quoteChar,
0993:                                        allowBackslashEscapes);
0994:
0995:                        if (limitStart == -1) {
0996:                            break;
0997:                        }
0998:
0999:                        currentPos = limitStart + 7;
1000:
1001:                        while (currentPos < statementLength) {
1002:                            char c = sql.charAt(currentPos);
1003:
1004:                            //
1005:                            // Have we reached the end
1006:                            // of what can be in a LIMIT clause?
1007:                            //
1008:
1009:                            if (!Character.isDigit(c)
1010:                                    && !Character.isWhitespace(c) && c != ','
1011:                                    && c != '?') {
1012:                                break;
1013:                            }
1014:
1015:                            if (c == '?') {
1016:                                foundLimitWithPlaceholder = true;
1017:                                break;
1018:                            }
1019:
1020:                            currentPos++;
1021:                        }
1022:                    }
1023:
1024:                    canHandleAsStatement = !foundLimitWithPlaceholder;
1025:                } else if (StringUtils.startsWithIgnoreCaseAndWs(sql,
1026:                        "CREATE TABLE")) {
1027:                    canHandleAsStatement = false;
1028:                } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "DO")) {
1029:                    canHandleAsStatement = false;
1030:                } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "SET")) {
1031:                    canHandleAsStatement = false;
1032:                }
1033:
1034:                return canHandleAsStatement;
1035:            }
1036:
1037:            /**
1038:             * Changes the user on this connection by performing a re-authentication. If
1039:             * authentication fails, the connection will remain under the context of the
1040:             * current user.
1041:             * 
1042:             * @param userName
1043:             *            the username to authenticate with
1044:             * @param newPassword
1045:             *            the password to authenticate with
1046:             * @throws SQLException
1047:             *             if authentication fails, or some other error occurs while
1048:             *             performing the command.
1049:             */
1050:            public void changeUser(String userName, String newPassword)
1051:                    throws SQLException {
1052:                if ((userName == null) || userName.equals("")) {
1053:                    userName = "";
1054:                }
1055:
1056:                if (newPassword == null) {
1057:                    newPassword = "";
1058:                }
1059:
1060:                this .io.changeUser(userName, newPassword, this .database);
1061:                this .user = userName;
1062:                this .password = newPassword;
1063:
1064:                if (versionMeetsMinimum(4, 1, 0)) {
1065:                    configureClientCharacterSet(true);
1066:                }
1067:
1068:                setupServerForTruncationChecks();
1069:            }
1070:
1071:            private boolean characterSetNamesMatches(String mysqlEncodingName) {
1072:                // set names is equivalent to character_set_client ..._results and ..._connection,
1073:                // but we set _results later, so don't check it here.
1074:
1075:                return (mysqlEncodingName != null
1076:                        && mysqlEncodingName
1077:                                .equalsIgnoreCase((String) this .serverVariables
1078:                                        .get("character_set_client")) && mysqlEncodingName
1079:                        .equalsIgnoreCase((String) this .serverVariables
1080:                                .get("character_set_connection")));
1081:            }
1082:
1083:            private void checkAndCreatePerformanceHistogram() {
1084:                if (this .perfMetricsHistCounts == null) {
1085:                    this .perfMetricsHistCounts = new int[HISTOGRAM_BUCKETS];
1086:                }
1087:
1088:                if (this .perfMetricsHistBreakpoints == null) {
1089:                    this .perfMetricsHistBreakpoints = new long[HISTOGRAM_BUCKETS];
1090:                }
1091:            }
1092:
1093:            private void checkAndCreateTablesAccessedHistogram() {
1094:                if (this .numTablesMetricsHistCounts == null) {
1095:                    this .numTablesMetricsHistCounts = new int[HISTOGRAM_BUCKETS];
1096:                }
1097:
1098:                if (this .numTablesMetricsHistBreakpoints == null) {
1099:                    this .numTablesMetricsHistBreakpoints = new long[HISTOGRAM_BUCKETS];
1100:                }
1101:            }
1102:
1103:            protected void checkClosed() throws SQLException {
1104:                if (this .isClosed) {
1105:                    StringBuffer messageBuf = new StringBuffer(
1106:                            "No operations allowed after connection closed.");
1107:
1108:                    if (this .forcedClosedLocation != null
1109:                            || this .forceClosedReason != null) {
1110:                        messageBuf.append("Connection was implicitly closed ");
1111:                    }
1112:
1113:                    if (this .forcedClosedLocation != null) {
1114:                        messageBuf.append("\n\n at (stack trace):\n");
1115:                        messageBuf.append(Util
1116:                                .stackTraceToString(this .forcedClosedLocation));
1117:                    }
1118:
1119:                    if (this .forceClosedReason != null) {
1120:                        if (this .forcedClosedLocation != null) {
1121:                            messageBuf.append("\n\nDue ");
1122:                        } else {
1123:                            messageBuf.append("due ");
1124:                        }
1125:
1126:                        messageBuf.append("to underlying exception/error:\n");
1127:                        messageBuf.append(Util
1128:                                .stackTraceToString(this .forceClosedReason));
1129:                    }
1130:
1131:                    throw SQLError.createSQLException(messageBuf.toString(),
1132:                            SQLError.SQL_STATE_CONNECTION_NOT_OPEN);
1133:                }
1134:            }
1135:
1136:            /**
1137:             * If useUnicode flag is set and explicit client character encoding isn't
1138:             * specified then assign encoding from server if any.
1139:             * 
1140:             * @throws SQLException
1141:             *             DOCUMENT ME!
1142:             */
1143:            private void checkServerEncoding() throws SQLException {
1144:                if (getUseUnicode() && (getEncoding() != null)) {
1145:                    // spec'd by client, don't map
1146:                    return;
1147:                }
1148:
1149:                String serverEncoding = (String) this .serverVariables
1150:                        .get("character_set");
1151:
1152:                if (serverEncoding == null) {
1153:                    // must be 4.1.1 or newer?
1154:                    serverEncoding = (String) this .serverVariables
1155:                            .get("character_set_server");
1156:                }
1157:
1158:                String mappedServerEncoding = null;
1159:
1160:                if (serverEncoding != null) {
1161:                    mappedServerEncoding = CharsetMapping
1162:                            .getJavaEncodingForMysqlEncoding(serverEncoding
1163:                                    .toUpperCase(Locale.ENGLISH), this );
1164:                }
1165:
1166:                //
1167:                // First check if we can do the encoding ourselves
1168:                //
1169:                if (!getUseUnicode() && (mappedServerEncoding != null)) {
1170:                    SingleByteCharsetConverter converter = getCharsetConverter(mappedServerEncoding);
1171:
1172:                    if (converter != null) { // we know how to convert this ourselves
1173:                        setUseUnicode(true); // force the issue
1174:                        setEncoding(mappedServerEncoding);
1175:
1176:                        return;
1177:                    }
1178:                }
1179:
1180:                //
1181:                // Now, try and find a Java I/O converter that can do
1182:                // the encoding for us
1183:                //
1184:                if (serverEncoding != null) {
1185:                    if (mappedServerEncoding == null) {
1186:                        // We don't have a mapping for it, so try
1187:                        // and canonicalize the name....
1188:                        if (Character.isLowerCase(serverEncoding.charAt(0))) {
1189:                            char[] ach = serverEncoding.toCharArray();
1190:                            ach[0] = Character.toUpperCase(serverEncoding
1191:                                    .charAt(0));
1192:                            setEncoding(new String(ach));
1193:                        }
1194:                    }
1195:
1196:                    if (mappedServerEncoding == null) {
1197:                        throw SQLError
1198:                                .createSQLException(
1199:                                        "Unknown character encoding on server '"
1200:                                                + serverEncoding
1201:                                                + "', use 'characterEncoding=' property "
1202:                                                + " to provide correct mapping",
1203:                                        SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
1204:                    }
1205:
1206:                    //
1207:                    // Attempt to use the encoding, and bail out if it
1208:                    // can't be used
1209:                    //
1210:                    try {
1211:                        "abc".getBytes(mappedServerEncoding);
1212:                        setEncoding(mappedServerEncoding);
1213:                        setUseUnicode(true);
1214:                    } catch (UnsupportedEncodingException UE) {
1215:                        throw SQLError
1216:                                .createSQLException(
1217:                                        "The driver can not map the character encoding '"
1218:                                                + getEncoding()
1219:                                                + "' that your server is using "
1220:                                                + "to a character encoding your JVM understands. You "
1221:                                                + "can specify this mapping manually by adding \"useUnicode=true\" "
1222:                                                + "as well as \"characterEncoding=[an_encoding_your_jvm_understands]\" "
1223:                                                + "to your JDBC URL.", "0S100");
1224:                    }
1225:                }
1226:            }
1227:
1228:            /**
1229:             * Set transaction isolation level to the value received from server if any.
1230:             * Is called by connectionInit(...)
1231:             * 
1232:             * @throws SQLException
1233:             *             DOCUMENT ME!
1234:             */
1235:            private void checkTransactionIsolationLevel() throws SQLException {
1236:                String txIsolationName = null;
1237:
1238:                if (versionMeetsMinimum(4, 0, 3)) {
1239:                    txIsolationName = "tx_isolation";
1240:                } else {
1241:                    txIsolationName = "transaction_isolation";
1242:                }
1243:
1244:                String s = (String) this .serverVariables.get(txIsolationName);
1245:
1246:                if (s != null) {
1247:                    Integer intTI = (Integer) mapTransIsolationNameToValue
1248:                            .get(s);
1249:
1250:                    if (intTI != null) {
1251:                        this .isolationLevel = intTI.intValue();
1252:                    }
1253:                }
1254:            }
1255:
1256:            /**
1257:             * Clobbers the physical network connection and marks
1258:             * this connection as closed.
1259:             * 
1260:             * @throws SQLException
1261:             */
1262:            protected void abortInternal() throws SQLException {
1263:                io.forceClose();
1264:                io = null;
1265:                isClosed = true;
1266:                cleanup(null);
1267:            }
1268:
1269:            /**
1270:             * Destroys this connection and any underlying resources
1271:             * 
1272:             * @param fromWhere
1273:             *            DOCUMENT ME!
1274:             * @param whyCleanedUp
1275:             *            DOCUMENT ME!
1276:             */
1277:            private void cleanup(Throwable whyCleanedUp) {
1278:                try {
1279:                    if ((this .io != null) && !isClosed()) {
1280:                        realClose(false, false, false, whyCleanedUp);
1281:                    } else if (this .io != null) {
1282:                        this .io.forceClose();
1283:                    }
1284:                } catch (SQLException sqlEx) {
1285:                    // ignore, we're going away.
1286:                    ;
1287:                }
1288:
1289:                this .isClosed = true;
1290:            }
1291:
1292:            public void clearHasTriedMaster() {
1293:                this .hasTriedMasterFlag = false;
1294:            }
1295:
1296:            /**
1297:             * After this call, getWarnings returns null until a new warning is reported
1298:             * for this connection.
1299:             * 
1300:             * @exception SQLException
1301:             *                if a database access error occurs
1302:             */
1303:            public void clearWarnings() throws SQLException {
1304:                // firstWarning = null;
1305:            }
1306:
1307:            /**
1308:             * DOCUMENT ME!
1309:             * 
1310:             * @param sql
1311:             *            DOCUMENT ME!
1312:             * @return DOCUMENT ME!
1313:             * @throws SQLException
1314:             *             DOCUMENT ME!
1315:             */
1316:            public PreparedStatement clientPrepareStatement(String sql)
1317:                    throws SQLException {
1318:                return clientPrepareStatement(sql,
1319:                        java.sql.ResultSet.TYPE_SCROLL_SENSITIVE,
1320:                        java.sql.ResultSet.CONCUR_READ_ONLY);
1321:            }
1322:
1323:            /**
1324:             * @see Connection#prepareStatement(String, int)
1325:             */
1326:            public java.sql.PreparedStatement clientPrepareStatement(
1327:                    String sql, int autoGenKeyIndex) throws SQLException {
1328:                java.sql.PreparedStatement pStmt = clientPrepareStatement(sql);
1329:
1330:                ((com.mysql.jdbc.PreparedStatement) pStmt)
1331:                        .setRetrieveGeneratedKeys(autoGenKeyIndex == java.sql.Statement.RETURN_GENERATED_KEYS);
1332:
1333:                return pStmt;
1334:            }
1335:
1336:            /**
1337:             * DOCUMENT ME!
1338:             * 
1339:             * @param sql
1340:             *            DOCUMENT ME!
1341:             * @param resultSetType
1342:             *            DOCUMENT ME!
1343:             * @param resultSetConcurrency
1344:             *            DOCUMENT ME!
1345:             * @return DOCUMENT ME!
1346:             * @throws SQLException
1347:             *             DOCUMENT ME!
1348:             */
1349:            public PreparedStatement clientPrepareStatement(String sql,
1350:                    int resultSetType, int resultSetConcurrency)
1351:                    throws SQLException {
1352:                return clientPrepareStatement(sql, resultSetType,
1353:                        resultSetConcurrency, true);
1354:            }
1355:
1356:            protected PreparedStatement clientPrepareStatement(String sql,
1357:                    int resultSetType, int resultSetConcurrency,
1358:                    boolean processEscapeCodesIfNeeded) throws SQLException {
1359:                checkClosed();
1360:
1361:                String nativeSql = processEscapeCodesIfNeeded
1362:                        && getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql)
1363:                        : sql;
1364:
1365:                PreparedStatement pStmt = null;
1366:
1367:                if (getCachePreparedStatements()) {
1368:                    synchronized (this .cachedPreparedStatementParams) {
1369:                        PreparedStatement.ParseInfo pStmtInfo = (PreparedStatement.ParseInfo) this .cachedPreparedStatementParams
1370:                                .get(nativeSql);
1371:
1372:                        if (pStmtInfo == null) {
1373:                            pStmt = com.mysql.jdbc.PreparedStatement
1374:                                    .getInstance(this , nativeSql, this .database);
1375:
1376:                            PreparedStatement.ParseInfo parseInfo = pStmt
1377:                                    .getParseInfo();
1378:
1379:                            if (parseInfo.statementLength < getPreparedStatementCacheSqlLimit()) {
1380:                                if (this .cachedPreparedStatementParams.size() >= getPreparedStatementCacheSize()) {
1381:                                    Iterator oldestIter = this .cachedPreparedStatementParams
1382:                                            .keySet().iterator();
1383:                                    long lruTime = Long.MAX_VALUE;
1384:                                    String oldestSql = null;
1385:
1386:                                    while (oldestIter.hasNext()) {
1387:                                        String sqlKey = (String) oldestIter
1388:                                                .next();
1389:                                        PreparedStatement.ParseInfo lruInfo = (PreparedStatement.ParseInfo) this .cachedPreparedStatementParams
1390:                                                .get(sqlKey);
1391:
1392:                                        if (lruInfo.lastUsed < lruTime) {
1393:                                            lruTime = lruInfo.lastUsed;
1394:                                            oldestSql = sqlKey;
1395:                                        }
1396:                                    }
1397:
1398:                                    if (oldestSql != null) {
1399:                                        this .cachedPreparedStatementParams
1400:                                                .remove(oldestSql);
1401:                                    }
1402:                                }
1403:
1404:                                this .cachedPreparedStatementParams.put(
1405:                                        nativeSql, pStmt.getParseInfo());
1406:                            }
1407:                        } else {
1408:                            pStmtInfo.lastUsed = System.currentTimeMillis();
1409:                            pStmt = new com.mysql.jdbc.PreparedStatement(this ,
1410:                                    nativeSql, this .database, pStmtInfo);
1411:                        }
1412:                    }
1413:                } else {
1414:                    pStmt = com.mysql.jdbc.PreparedStatement.getInstance(this ,
1415:                            nativeSql, this .database);
1416:                }
1417:
1418:                pStmt.setResultSetType(resultSetType);
1419:                pStmt.setResultSetConcurrency(resultSetConcurrency);
1420:
1421:                return pStmt;
1422:            }
1423:
1424:            /**
1425:             * @see java.sql.Connection#prepareStatement(String, int[])
1426:             */
1427:            public java.sql.PreparedStatement clientPrepareStatement(
1428:                    String sql, int[] autoGenKeyIndexes) throws SQLException {
1429:
1430:                PreparedStatement pStmt = clientPrepareStatement(sql);
1431:
1432:                pStmt.setRetrieveGeneratedKeys((autoGenKeyIndexes != null)
1433:                        && (autoGenKeyIndexes.length > 0));
1434:
1435:                return pStmt;
1436:            }
1437:
1438:            /**
1439:             * @see java.sql.Connection#prepareStatement(String, String[])
1440:             */
1441:            public java.sql.PreparedStatement clientPrepareStatement(
1442:                    String sql, String[] autoGenKeyColNames)
1443:                    throws SQLException {
1444:                PreparedStatement pStmt = clientPrepareStatement(sql);
1445:
1446:                pStmt.setRetrieveGeneratedKeys((autoGenKeyColNames != null)
1447:                        && (autoGenKeyColNames.length > 0));
1448:
1449:                return pStmt;
1450:            }
1451:
1452:            // --------------------------JDBC 2.0-----------------------------
1453:
1454:            /**
1455:             * In some cases, it is desirable to immediately release a Connection's
1456:             * database and JDBC resources instead of waiting for them to be
1457:             * automatically released (cant think why off the top of my head) <B>Note:</B>
1458:             * A Connection is automatically closed when it is garbage collected.
1459:             * Certain fatal errors also result in a closed connection.
1460:             * 
1461:             * @exception SQLException
1462:             *                if a database access error occurs
1463:             */
1464:            public void close() throws SQLException {
1465:                realClose(true, true, false, null);
1466:            }
1467:
1468:            /**
1469:             * Closes all currently open statements.
1470:             * 
1471:             * @throws SQLException
1472:             *             DOCUMENT ME!
1473:             */
1474:            private void closeAllOpenStatements() throws SQLException {
1475:                SQLException postponedException = null;
1476:
1477:                if (this .openStatements != null) {
1478:                    List currentlyOpenStatements = new ArrayList(); // we need this to
1479:                    // avoid
1480:                    // ConcurrentModificationEx
1481:
1482:                    for (Iterator iter = this .openStatements.keySet()
1483:                            .iterator(); iter.hasNext();) {
1484:                        currentlyOpenStatements.add(iter.next());
1485:                    }
1486:
1487:                    int numStmts = currentlyOpenStatements.size();
1488:
1489:                    for (int i = 0; i < numStmts; i++) {
1490:                        StatementImpl stmt = (StatementImpl) currentlyOpenStatements
1491:                                .get(i);
1492:
1493:                        try {
1494:                            stmt.realClose(false, true);
1495:                        } catch (SQLException sqlEx) {
1496:                            postponedException = sqlEx; // throw it later, cleanup all
1497:                            // statements first
1498:                        }
1499:                    }
1500:
1501:                    if (postponedException != null) {
1502:                        throw postponedException;
1503:                    }
1504:                }
1505:            }
1506:
1507:            private void closeStatement(java.sql.Statement stmt) {
1508:                if (stmt != null) {
1509:                    try {
1510:                        stmt.close();
1511:                    } catch (SQLException sqlEx) {
1512:                        ; // ignore
1513:                    }
1514:
1515:                    stmt = null;
1516:                }
1517:            }
1518:
1519:            /**
1520:             * The method commit() makes all changes made since the previous
1521:             * commit/rollback permanent and releases any database locks currently held
1522:             * by the Connection. This method should only be used when auto-commit has
1523:             * been disabled.
1524:             * <p>
1525:             * <b>Note:</b> MySQL does not support transactions, so this method is a
1526:             * no-op.
1527:             * </p>
1528:             * 
1529:             * @exception SQLException
1530:             *                if a database access error occurs
1531:             * @see setAutoCommit
1532:             */
1533:            public void commit() throws SQLException {
1534:                synchronized (getMutex()) {
1535:                    checkClosed();
1536:
1537:                    try {
1538:                        // no-op if _relaxAutoCommit == true
1539:                        if (this .autoCommit && !getRelaxAutoCommit()) {
1540:                            throw SQLError
1541:                                    .createSQLException("Can't call commit when autocommit=true");
1542:                        } else if (this .transactionsSupported) {
1543:                            if (getUseLocalSessionState()
1544:                                    && versionMeetsMinimum(5, 0, 0)) {
1545:                                if (!this .io.inTransactionOnServer()) {
1546:                                    return; // effectively a no-op
1547:                                }
1548:                            }
1549:
1550:                            execSQL(null, "commit", -1, null,
1551:                                    java.sql.ResultSet.TYPE_FORWARD_ONLY,
1552:                                    java.sql.ResultSet.CONCUR_READ_ONLY, false,
1553:                                    this .database, null, false);
1554:                        }
1555:                    } catch (SQLException sqlException) {
1556:                        if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
1557:                                .equals(sqlException.getSQLState())) {
1558:                            throw SQLError
1559:                                    .createSQLException(
1560:                                            "Communications link failure during commit(). Transaction resolution unknown.",
1561:                                            SQLError.SQL_STATE_TRANSACTION_RESOLUTION_UNKNOWN);
1562:                        }
1563:
1564:                        throw sqlException;
1565:                    } finally {
1566:                        this .needsPing = this .getReconnectAtTxEnd();
1567:                    }
1568:
1569:                    return;
1570:                }
1571:            }
1572:
1573:            /**
1574:             * Configures client-side properties for character set information.
1575:             * 
1576:             * @throws SQLException
1577:             *             if unable to configure the specified character set.
1578:             */
1579:            private void configureCharsetProperties() throws SQLException {
1580:                if (getEncoding() != null) {
1581:                    // Attempt to use the encoding, and bail out if it
1582:                    // can't be used
1583:                    try {
1584:                        String testString = "abc";
1585:                        testString.getBytes(getEncoding());
1586:                    } catch (UnsupportedEncodingException UE) {
1587:                        // Try the MySQL character encoding, then....
1588:                        String oldEncoding = getEncoding();
1589:
1590:                        setEncoding(CharsetMapping
1591:                                .getJavaEncodingForMysqlEncoding(oldEncoding,
1592:                                        this ));
1593:
1594:                        if (getEncoding() == null) {
1595:                            throw SQLError
1596:                                    .createSQLException(
1597:                                            "Java does not support the MySQL character encoding "
1598:                                                    + " " + "encoding '"
1599:                                                    + oldEncoding + "'.",
1600:                                            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
1601:                        }
1602:
1603:                        try {
1604:                            String testString = "abc";
1605:                            testString.getBytes(getEncoding());
1606:                        } catch (UnsupportedEncodingException encodingEx) {
1607:                            throw SQLError
1608:                                    .createSQLException(
1609:                                            "Unsupported character "
1610:                                                    + "encoding '"
1611:                                                    + getEncoding() + "'.",
1612:                                            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
1613:                        }
1614:                    }
1615:                }
1616:            }
1617:
1618:            /**
1619:             * Sets up client character set for MySQL-4.1 and newer if the user This
1620:             * must be done before any further communication with the server!
1621:             * 
1622:             * @return true if this routine actually configured the client character
1623:             *         set, or false if the driver needs to use 'older' methods to
1624:             *         detect the character set, as it is connected to a MySQL server
1625:             *         older than 4.1.0
1626:             * @throws SQLException
1627:             *             if an exception happens while sending 'SET NAMES' to the
1628:             *             server, or the server sends character set information that
1629:             *             the client doesn't know about.
1630:             */
1631:            private boolean configureClientCharacterSet(
1632:                    boolean dontCheckServerMatch) throws SQLException {
1633:                String realJavaEncoding = getEncoding();
1634:                boolean characterSetAlreadyConfigured = false;
1635:
1636:                try {
1637:                    if (versionMeetsMinimum(4, 1, 0)) {
1638:                        characterSetAlreadyConfigured = true;
1639:
1640:                        setUseUnicode(true);
1641:
1642:                        configureCharsetProperties();
1643:                        realJavaEncoding = getEncoding(); // we need to do this again
1644:                        // to grab this for
1645:                        // versions > 4.1.0
1646:
1647:                        try {
1648:
1649:                            // Fault injection for testing server character set indices
1650:
1651:                            if (props != null
1652:                                    && props
1653:                                            .getProperty("com.mysql.jdbc.faultInjection.serverCharsetIndex") != null) {
1654:                                this .io.serverCharsetIndex = Integer
1655:                                        .parseInt(props
1656:                                                .getProperty("com.mysql.jdbc.faultInjection.serverCharsetIndex"));
1657:                            }
1658:
1659:                            String serverEncodingToSet = CharsetMapping.INDEX_TO_CHARSET[this .io.serverCharsetIndex];
1660:
1661:                            if (serverEncodingToSet == null
1662:                                    || serverEncodingToSet.length() == 0) {
1663:                                if (realJavaEncoding != null) {
1664:                                    // user knows best, try it
1665:                                    setEncoding(realJavaEncoding);
1666:                                } else {
1667:                                    throw SQLError
1668:                                            .createSQLException(
1669:                                                    "Unknown initial character set index '"
1670:                                                            + this .io.serverCharsetIndex
1671:                                                            + "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
1672:                                                    SQLError.SQL_STATE_GENERAL_ERROR);
1673:                                }
1674:                            }
1675:
1676:                            // "latin1" on MySQL-4.1.0+ is actually CP1252, not ISO8859_1
1677:                            if (versionMeetsMinimum(4, 1, 0)
1678:                                    && "ISO8859_1"
1679:                                            .equalsIgnoreCase(serverEncodingToSet)) {
1680:                                serverEncodingToSet = "Cp1252";
1681:                            }
1682:
1683:                            setEncoding(serverEncodingToSet);
1684:
1685:                        } catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
1686:                            if (realJavaEncoding != null) {
1687:                                // user knows best, try it
1688:                                setEncoding(realJavaEncoding);
1689:                            } else {
1690:                                throw SQLError
1691:                                        .createSQLException(
1692:                                                "Unknown initial character set index '"
1693:                                                        + this .io.serverCharsetIndex
1694:                                                        + "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
1695:                                                SQLError.SQL_STATE_GENERAL_ERROR);
1696:                            }
1697:                        }
1698:
1699:                        if (getEncoding() == null) {
1700:                            // punt?
1701:                            setEncoding("ISO8859_1");
1702:                        }
1703:
1704:                        //
1705:                        // Has the user has 'forced' the character encoding via
1706:                        // driver properties?
1707:                        //
1708:                        if (getUseUnicode()) {
1709:                            if (realJavaEncoding != null) {
1710:
1711:                                //
1712:                                // Now, inform the server what character set we
1713:                                // will be using from now-on...
1714:                                //
1715:                                if (realJavaEncoding.equalsIgnoreCase("UTF-8")
1716:                                        || realJavaEncoding
1717:                                                .equalsIgnoreCase("UTF8")) {
1718:                                    // charset names are case-sensitive
1719:
1720:                                    if (!getUseOldUTF8Behavior()) {
1721:                                        if (dontCheckServerMatch
1722:                                                || !characterSetNamesMatches("utf8")) {
1723:                                            execSQL(
1724:                                                    null,
1725:                                                    "SET NAMES utf8",
1726:                                                    -1,
1727:                                                    null,
1728:                                                    java.sql.ResultSet.TYPE_FORWARD_ONLY,
1729:                                                    java.sql.ResultSet.CONCUR_READ_ONLY,
1730:                                                    false, this .database, null,
1731:                                                    false);
1732:                                        }
1733:                                    }
1734:
1735:                                    setEncoding(realJavaEncoding);
1736:                                } /* not utf-8 */else {
1737:                                    String mysqlEncodingName = CharsetMapping
1738:                                            .getMysqlEncodingForJavaEncoding(
1739:                                                    realJavaEncoding
1740:                                                            .toUpperCase(Locale.ENGLISH),
1741:                                                    this );
1742:
1743:                                    /*
1744:                                     * if ("koi8_ru".equals(mysqlEncodingName)) { //
1745:                                     * This has a _different_ name in 4.1...
1746:                                     * mysqlEncodingName = "ko18r"; } else if
1747:                                     * ("euc_kr".equals(mysqlEncodingName)) { //
1748:                                     * Different name in 4.1 mysqlEncodingName =
1749:                                     * "euckr"; }
1750:                                     */
1751:
1752:                                    if (mysqlEncodingName != null) {
1753:
1754:                                        if (dontCheckServerMatch
1755:                                                || !characterSetNamesMatches(mysqlEncodingName)) {
1756:                                            execSQL(
1757:                                                    null,
1758:                                                    "SET NAMES "
1759:                                                            + mysqlEncodingName,
1760:                                                    -1,
1761:                                                    null,
1762:                                                    java.sql.ResultSet.TYPE_FORWARD_ONLY,
1763:                                                    java.sql.ResultSet.CONCUR_READ_ONLY,
1764:                                                    false, this .database, null,
1765:                                                    false);
1766:                                        }
1767:                                    }
1768:
1769:                                    // Switch driver's encoding now, since the server
1770:                                    // knows what we're sending...
1771:                                    //
1772:                                    setEncoding(realJavaEncoding);
1773:                                }
1774:                            } else if (getEncoding() != null) {
1775:                                // Tell the server we'll use the server default charset
1776:                                // to send our
1777:                                // queries from now on....
1778:                                String mysqlEncodingName = CharsetMapping
1779:                                        .getMysqlEncodingForJavaEncoding(
1780:                                                getEncoding().toUpperCase(
1781:                                                        Locale.ENGLISH), this );
1782:
1783:                                if (dontCheckServerMatch
1784:                                        || !characterSetNamesMatches(mysqlEncodingName)) {
1785:                                    execSQL(
1786:                                            null,
1787:                                            "SET NAMES " + mysqlEncodingName,
1788:                                            -1,
1789:                                            null,
1790:                                            java.sql.ResultSet.TYPE_FORWARD_ONLY,
1791:                                            java.sql.ResultSet.CONCUR_READ_ONLY,
1792:                                            false, this .database, null, false);
1793:                                }
1794:
1795:                                realJavaEncoding = getEncoding();
1796:                            }
1797:
1798:                        }
1799:
1800:                        //
1801:                        // We know how to deal with any charset coming back from
1802:                        // the database, so tell the server not to do conversion
1803:                        // if the user hasn't 'forced' a result-set character set
1804:                        //
1805:
1806:                        String onServer = null;
1807:                        boolean isNullOnServer = false;
1808:
1809:                        if (this .serverVariables != null) {
1810:                            onServer = (String) this .serverVariables
1811:                                    .get("character_set_results");
1812:
1813:                            isNullOnServer = onServer == null
1814:                                    || "NULL".equalsIgnoreCase(onServer)
1815:                                    || onServer.length() == 0;
1816:                        }
1817:
1818:                        if (getCharacterSetResults() == null) {
1819:
1820:                            //
1821:                            // Only send if needed, if we're caching server variables
1822:                            // we -have- to send, because we don't know what it was
1823:                            // before we cached them.
1824:                            //
1825:                            if (!isNullOnServer) {
1826:                                execSQL(null,
1827:                                        "SET character_set_results = NULL", -1,
1828:                                        null,
1829:                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
1830:                                        java.sql.ResultSet.CONCUR_READ_ONLY,
1831:                                        false, this .database, null, false);
1832:                                if (!this .usingCachedConfig) {
1833:                                    this .serverVariables.put(
1834:                                            JDBC_LOCAL_CHARACTER_SET_RESULTS,
1835:                                            null);
1836:                                }
1837:                            } else {
1838:                                if (!this .usingCachedConfig) {
1839:                                    this .serverVariables.put(
1840:                                            JDBC_LOCAL_CHARACTER_SET_RESULTS,
1841:                                            onServer);
1842:                                }
1843:                            }
1844:                        } else {
1845:                            String charsetResults = getCharacterSetResults();
1846:                            String mysqlEncodingName = null;
1847:
1848:                            if ("UTF-8".equalsIgnoreCase(charsetResults)
1849:                                    || "UTF8".equalsIgnoreCase(charsetResults)) {
1850:                                mysqlEncodingName = "utf8";
1851:                            } else {
1852:                                mysqlEncodingName = CharsetMapping
1853:                                        .getMysqlEncodingForJavaEncoding(
1854:                                                charsetResults
1855:                                                        .toUpperCase(Locale.ENGLISH),
1856:                                                this );
1857:                            }
1858:
1859:                            //
1860:                            // Only change the value if needed
1861:                            //
1862:
1863:                            if (!mysqlEncodingName
1864:                                    .equalsIgnoreCase((String) this .serverVariables
1865:                                            .get("character_set_results"))) {
1866:                                StringBuffer setBuf = new StringBuffer(
1867:                                        "SET character_set_results = ".length()
1868:                                                + mysqlEncodingName.length());
1869:                                setBuf.append("SET character_set_results = ")
1870:                                        .append(mysqlEncodingName);
1871:
1872:                                execSQL(null, setBuf.toString(), -1, null,
1873:                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
1874:                                        java.sql.ResultSet.CONCUR_READ_ONLY,
1875:                                        false, this .database, null, false);
1876:
1877:                                if (!this .usingCachedConfig) {
1878:                                    this .serverVariables.put(
1879:                                            JDBC_LOCAL_CHARACTER_SET_RESULTS,
1880:                                            mysqlEncodingName);
1881:                                }
1882:                            } else {
1883:                                if (!this .usingCachedConfig) {
1884:                                    this .serverVariables.put(
1885:                                            JDBC_LOCAL_CHARACTER_SET_RESULTS,
1886:                                            onServer);
1887:                                }
1888:                            }
1889:                        }
1890:
1891:                        if (getConnectionCollation() != null) {
1892:                            StringBuffer setBuf = new StringBuffer(
1893:                                    "SET collation_connection = ".length()
1894:                                            + getConnectionCollation().length());
1895:                            setBuf.append("SET collation_connection = ")
1896:                                    .append(getConnectionCollation());
1897:
1898:                            execSQL(null, setBuf.toString(), -1, null,
1899:                                    java.sql.ResultSet.TYPE_FORWARD_ONLY,
1900:                                    java.sql.ResultSet.CONCUR_READ_ONLY, false,
1901:                                    this .database, null, false);
1902:                        }
1903:                    } else {
1904:                        // Use what the server has specified
1905:                        realJavaEncoding = getEncoding(); // so we don't get
1906:                        // swapped out in the finally
1907:                        // block....
1908:                    }
1909:                } finally {
1910:                    // Failsafe, make sure that the driver's notion of character
1911:                    // encoding matches what the user has specified.
1912:                    //
1913:                    setEncoding(realJavaEncoding);
1914:                }
1915:
1916:                return characterSetAlreadyConfigured;
1917:            }
1918:
1919:            /**
1920:             * Configures the client's timezone if required.
1921:             * 
1922:             * @throws SQLException
1923:             *             if the timezone the server is configured to use can't be
1924:             *             mapped to a Java timezone.
1925:             */
1926:            private void configureTimezone() throws SQLException {
1927:                String configuredTimeZoneOnServer = (String) this .serverVariables
1928:                        .get("timezone");
1929:
1930:                if (configuredTimeZoneOnServer == null) {
1931:                    configuredTimeZoneOnServer = (String) this .serverVariables
1932:                            .get("time_zone");
1933:
1934:                    if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
1935:                        configuredTimeZoneOnServer = (String) this .serverVariables
1936:                                .get("system_time_zone");
1937:                    }
1938:                }
1939:
1940:                if (getUseTimezone() && configuredTimeZoneOnServer != null) {
1941:                    // user can specify/override as property
1942:                    String canoncicalTimezone = getServerTimezone();
1943:
1944:                    if ((canoncicalTimezone == null)
1945:                            || (canoncicalTimezone.length() == 0)) {
1946:                        String serverTimezoneStr = configuredTimeZoneOnServer;
1947:
1948:                        try {
1949:                            canoncicalTimezone = TimeUtil
1950:                                    .getCanoncialTimezone(serverTimezoneStr);
1951:
1952:                            if (canoncicalTimezone == null) {
1953:                                throw SQLError.createSQLException(
1954:                                        "Can't map timezone '"
1955:                                                + serverTimezoneStr + "' to "
1956:                                                + " canonical timezone.",
1957:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1958:                            }
1959:                        } catch (IllegalArgumentException iae) {
1960:                            throw SQLError.createSQLException(iae.getMessage(),
1961:                                    SQLError.SQL_STATE_GENERAL_ERROR);
1962:                        }
1963:                    }
1964:
1965:                    this .serverTimezoneTZ = TimeZone
1966:                            .getTimeZone(canoncicalTimezone);
1967:
1968:                    //
1969:                    // The Calendar class has the behavior of mapping
1970:                    // unknown timezones to 'GMT' instead of throwing an
1971:                    // exception, so we must check for this...
1972:                    //
1973:                    if (!canoncicalTimezone.equalsIgnoreCase("GMT")
1974:                            && this .serverTimezoneTZ.getID().equals("GMT")) {
1975:                        throw SQLError.createSQLException(
1976:                                "No timezone mapping entry for '"
1977:                                        + canoncicalTimezone + "'",
1978:                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1979:                    }
1980:
1981:                    if ("GMT".equalsIgnoreCase(this .serverTimezoneTZ.getID())) {
1982:                        this .isServerTzUTC = true;
1983:                    } else {
1984:                        this .isServerTzUTC = false;
1985:                    }
1986:                }
1987:            }
1988:
1989:            private void createInitialHistogram(long[] breakpoints,
1990:                    long lowerBound, long upperBound) {
1991:
1992:                double bucketSize = (((double) upperBound - (double) lowerBound) / HISTOGRAM_BUCKETS) * 1.25;
1993:
1994:                if (bucketSize < 1) {
1995:                    bucketSize = 1;
1996:                }
1997:
1998:                for (int i = 0; i < HISTOGRAM_BUCKETS; i++) {
1999:                    breakpoints[i] = lowerBound;
2000:                    lowerBound += bucketSize;
2001:                }
2002:            }
2003:
2004:            /**
2005:             * Creates an IO channel to the server
2006:             * 
2007:             * @param isForReconnect
2008:             *            is this request for a re-connect
2009:             * @return a new MysqlIO instance connected to a server
2010:             * @throws SQLException
2011:             *             if a database access error occurs
2012:             * @throws CommunicationsException
2013:             *             DOCUMENT ME!
2014:             */
2015:            protected void createNewIO(boolean isForReconnect)
2016:                    throws SQLException {
2017:                Properties mergedProps = exposeAsProperties(this .props);
2018:
2019:                long queriesIssuedFailedOverCopy = this .queriesIssuedFailedOver;
2020:                this .queriesIssuedFailedOver = 0;
2021:
2022:                try {
2023:                    if (!getHighAvailability() && !this .failedOver) {
2024:                        boolean connectionGood = false;
2025:                        Exception connectionNotEstablishedBecause = null;
2026:
2027:                        int hostIndex = 0;
2028:
2029:                        //
2030:                        // TODO: Eventually, when there's enough metadata
2031:                        // on the server to support it, we should come up
2032:                        // with a smarter way to pick what server to connect
2033:                        // to...perhaps even making it 'pluggable'
2034:                        //
2035:                        if (getRoundRobinLoadBalance()) {
2036:                            hostIndex = getNextRoundRobinHostIndex(getURL(),
2037:                                    this .hostList);
2038:                        }
2039:
2040:                        for (; hostIndex < this .hostListSize; hostIndex++) {
2041:
2042:                            if (hostIndex == 0) {
2043:                                this .hasTriedMasterFlag = true;
2044:                            }
2045:
2046:                            try {
2047:                                String newHostPortPair = (String) this .hostList
2048:                                        .get(hostIndex);
2049:
2050:                                int newPort = 3306;
2051:
2052:                                String[] hostPortPair = NonRegisteringDriver
2053:                                        .parseHostPortPair(newHostPortPair);
2054:                                String newHost = hostPortPair[NonRegisteringDriver.HOST_NAME_INDEX];
2055:
2056:                                if (newHost == null
2057:                                        || StringUtils
2058:                                                .isEmptyOrWhitespaceOnly(newHost)) {
2059:                                    newHost = "localhost";
2060:                                }
2061:
2062:                                if (hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] != null) {
2063:                                    try {
2064:                                        newPort = Integer
2065:                                                .parseInt(hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]);
2066:                                    } catch (NumberFormatException nfe) {
2067:                                        throw SQLError
2068:                                                .createSQLException(
2069:                                                        "Illegal connection port value '"
2070:                                                                + hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]
2071:                                                                + "'",
2072:                                                        SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
2073:                                    }
2074:                                }
2075:
2076:                                this .io = new MysqlIO(newHost, newPort,
2077:                                        mergedProps,
2078:                                        getSocketFactoryClassName(), this ,
2079:                                        getSocketTimeout(),
2080:                                        this .largeRowSizeThreshold
2081:                                                .getValueAsInt());
2082:
2083:                                this .io.doHandshake(this .user, this .password,
2084:                                        this .database);
2085:                                this .connectionId = this .io.getThreadId();
2086:                                this .isClosed = false;
2087:
2088:                                // save state from old connection
2089:                                boolean oldAutoCommit = getAutoCommit();
2090:                                int oldIsolationLevel = this .isolationLevel;
2091:                                boolean oldReadOnly = isReadOnly();
2092:                                String oldCatalog = getCatalog();
2093:
2094:                                // Server properties might be different
2095:                                // from previous connection, so initialize
2096:                                // again...
2097:                                initializePropsFromServer();
2098:
2099:                                if (isForReconnect) {
2100:                                    // Restore state from old connection
2101:                                    setAutoCommit(oldAutoCommit);
2102:
2103:                                    if (this .hasIsolationLevels) {
2104:                                        setTransactionIsolation(oldIsolationLevel);
2105:                                    }
2106:
2107:                                    setCatalog(oldCatalog);
2108:                                }
2109:
2110:                                if (hostIndex != 0) {
2111:                                    setFailedOverState();
2112:                                    queriesIssuedFailedOverCopy = 0;
2113:                                } else {
2114:                                    this .failedOver = false;
2115:                                    queriesIssuedFailedOverCopy = 0;
2116:
2117:                                    if (this .hostListSize > 1) {
2118:                                        setReadOnlyInternal(false);
2119:                                    } else {
2120:                                        setReadOnlyInternal(oldReadOnly);
2121:                                    }
2122:                                }
2123:
2124:                                connectionGood = true;
2125:
2126:                                break; // low-level connection succeeded
2127:                            } catch (Exception EEE) {
2128:                                if (this .io != null) {
2129:                                    this .io.forceClose();
2130:                                }
2131:
2132:                                connectionNotEstablishedBecause = EEE;
2133:
2134:                                connectionGood = false;
2135:
2136:                                if (EEE instanceof  SQLException) {
2137:                                    SQLException sqlEx = (SQLException) EEE;
2138:
2139:                                    String sqlState = sqlEx.getSQLState();
2140:
2141:                                    // If this isn't a communications failure, it will probably never succeed, so
2142:                                    // give up right here and now ....
2143:                                    if ((sqlState == null)
2144:                                            || !sqlState
2145:                                                    .equals(SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)) {
2146:                                        throw sqlEx;
2147:                                    }
2148:                                }
2149:
2150:                                // Check next host, it might be up...
2151:                                if (getRoundRobinLoadBalance()) {
2152:                                    hostIndex = getNextRoundRobinHostIndex(
2153:                                            getURL(), this .hostList) - 1 /* incremented by for loop next time around */;
2154:                                } else if ((this .hostListSize - 1) == hostIndex) {
2155:                                    throw SQLError
2156:                                            .createCommunicationsException(
2157:                                                    this ,
2158:                                                    (this .io != null) ? this .io
2159:                                                            .getLastPacketSentTimeMs()
2160:                                                            : 0, EEE);
2161:                                }
2162:                            }
2163:                        }
2164:
2165:                        if (!connectionGood) {
2166:                            // We've really failed!
2167:                            throw SQLError
2168:                                    .createSQLException(
2169:                                            "Could not create connection to database server due to underlying exception: '"
2170:                                                    + connectionNotEstablishedBecause
2171:                                                    + "'."
2172:                                                    + (getParanoid() ? ""
2173:                                                            : Util
2174:                                                                    .stackTraceToString(connectionNotEstablishedBecause)),
2175:                                            SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
2176:                        }
2177:                    } else {
2178:                        double timeout = getInitialTimeout();
2179:                        boolean connectionGood = false;
2180:
2181:                        Exception connectionException = null;
2182:
2183:                        int hostIndex = 0;
2184:
2185:                        if (getRoundRobinLoadBalance()) {
2186:                            hostIndex = getNextRoundRobinHostIndex(getURL(),
2187:                                    this .hostList);
2188:                        }
2189:
2190:                        for (; (hostIndex < this .hostListSize)
2191:                                && !connectionGood; hostIndex++) {
2192:                            if (hostIndex == 0) {
2193:                                this .hasTriedMasterFlag = true;
2194:                            }
2195:
2196:                            if (this .preferSlaveDuringFailover
2197:                                    && hostIndex == 0) {
2198:                                hostIndex++;
2199:                            }
2200:
2201:                            for (int attemptCount = 0; (attemptCount < getMaxReconnects())
2202:                                    && !connectionGood; attemptCount++) {
2203:                                try {
2204:                                    if (this .io != null) {
2205:                                        this .io.forceClose();
2206:                                    }
2207:
2208:                                    String newHostPortPair = (String) this .hostList
2209:                                            .get(hostIndex);
2210:
2211:                                    int newPort = 3306;
2212:
2213:                                    String[] hostPortPair = NonRegisteringDriver
2214:                                            .parseHostPortPair(newHostPortPair);
2215:                                    String newHost = hostPortPair[NonRegisteringDriver.HOST_NAME_INDEX];
2216:
2217:                                    if (newHost == null
2218:                                            || StringUtils
2219:                                                    .isEmptyOrWhitespaceOnly(newHost)) {
2220:                                        newHost = "localhost";
2221:                                    }
2222:
2223:                                    if (hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] != null) {
2224:                                        try {
2225:                                            newPort = Integer
2226:                                                    .parseInt(hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]);
2227:                                        } catch (NumberFormatException nfe) {
2228:                                            throw SQLError
2229:                                                    .createSQLException(
2230:                                                            "Illegal connection port value '"
2231:                                                                    + hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]
2232:                                                                    + "'",
2233:                                                            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
2234:                                        }
2235:                                    }
2236:
2237:                                    this .io = new MysqlIO(newHost, newPort,
2238:                                            mergedProps,
2239:                                            getSocketFactoryClassName(), this ,
2240:                                            getSocketTimeout(),
2241:                                            this .largeRowSizeThreshold
2242:                                                    .getValueAsInt());
2243:                                    this .io.doHandshake(this .user,
2244:                                            this .password, this .database);
2245:                                    pingInternal(false);
2246:                                    this .connectionId = this .io.getThreadId();
2247:                                    this .isClosed = false;
2248:
2249:                                    // save state from old connection
2250:                                    boolean oldAutoCommit = getAutoCommit();
2251:                                    int oldIsolationLevel = this .isolationLevel;
2252:                                    boolean oldReadOnly = isReadOnly();
2253:                                    String oldCatalog = getCatalog();
2254:
2255:                                    // Server properties might be different
2256:                                    // from previous connection, so initialize
2257:                                    // again...
2258:                                    initializePropsFromServer();
2259:
2260:                                    if (isForReconnect) {
2261:                                        // Restore state from old connection
2262:                                        setAutoCommit(oldAutoCommit);
2263:
2264:                                        if (this .hasIsolationLevels) {
2265:                                            setTransactionIsolation(oldIsolationLevel);
2266:                                        }
2267:
2268:                                        setCatalog(oldCatalog);
2269:                                    }
2270:
2271:                                    connectionGood = true;
2272:
2273:                                    if (hostIndex != 0) {
2274:                                        setFailedOverState();
2275:                                        queriesIssuedFailedOverCopy = 0;
2276:                                    } else {
2277:                                        this .failedOver = false;
2278:                                        queriesIssuedFailedOverCopy = 0;
2279:
2280:                                        if (this .hostListSize > 1) {
2281:                                            setReadOnlyInternal(false);
2282:                                        } else {
2283:                                            setReadOnlyInternal(oldReadOnly);
2284:                                        }
2285:                                    }
2286:
2287:                                    break;
2288:                                } catch (Exception EEE) {
2289:                                    connectionException = EEE;
2290:                                    connectionGood = false;
2291:
2292:                                    // Check next host, it might be up...
2293:                                    if (getRoundRobinLoadBalance()) {
2294:                                        hostIndex = getNextRoundRobinHostIndex(
2295:                                                getURL(), this .hostList) - 1 /* incremented by for loop next time around */;
2296:                                    }
2297:                                }
2298:
2299:                                if (connectionGood) {
2300:                                    break;
2301:                                }
2302:
2303:                                if (attemptCount > 0) {
2304:                                    try {
2305:                                        Thread.sleep((long) timeout * 1000);
2306:                                    } catch (InterruptedException IE) {
2307:                                        // ignore
2308:                                    }
2309:                                }
2310:                            } // end attempts for a single host
2311:                        } // end iterator for list of hosts
2312:
2313:                        if (!connectionGood) {
2314:                            // We've really failed!
2315:                            throw SQLError
2316:                                    .createSQLException(
2317:                                            "Server connection failure during transaction. Due to underlying exception: '"
2318:                                                    + connectionException
2319:                                                    + "'."
2320:                                                    + (getParanoid() ? ""
2321:                                                            : Util
2322:                                                                    .stackTraceToString(connectionException))
2323:                                                    + "\nAttempted reconnect "
2324:                                                    + getMaxReconnects()
2325:                                                    + " times. Giving up.",
2326:                                            SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
2327:                        }
2328:                    }
2329:
2330:                    if (getParanoid() && !getHighAvailability()
2331:                            && (this .hostListSize <= 1)) {
2332:                        this .password = null;
2333:                        this .user = null;
2334:                    }
2335:
2336:                    if (isForReconnect) {
2337:                        //
2338:                        // Retrieve any 'lost' prepared statements if re-connecting
2339:                        //
2340:                        Iterator statementIter = this .openStatements.values()
2341:                                .iterator();
2342:
2343:                        //
2344:                        // We build a list of these outside the map of open statements,
2345:                        // because
2346:                        // in the process of re-preparing, we might end up having to
2347:                        // close
2348:                        // a prepared statement, thus removing it from the map, and
2349:                        // generating
2350:                        // a ConcurrentModificationException
2351:                        //
2352:                        Stack serverPreparedStatements = null;
2353:
2354:                        while (statementIter.hasNext()) {
2355:                            Object statementObj = statementIter.next();
2356:
2357:                            if (statementObj instanceof  ServerPreparedStatement) {
2358:                                if (serverPreparedStatements == null) {
2359:                                    serverPreparedStatements = new Stack();
2360:                                }
2361:
2362:                                serverPreparedStatements.add(statementObj);
2363:                            }
2364:                        }
2365:
2366:                        if (serverPreparedStatements != null) {
2367:                            while (!serverPreparedStatements.isEmpty()) {
2368:                                ((ServerPreparedStatement) serverPreparedStatements
2369:                                        .pop()).rePrepare();
2370:                            }
2371:                        }
2372:                    }
2373:                } finally {
2374:                    this .queriesIssuedFailedOver = queriesIssuedFailedOverCopy;
2375:
2376:                    if (this .io != null && getStatementInterceptors() != null) {
2377:                        this .io.initializeStatementInterceptors(
2378:                                getStatementInterceptors(), mergedProps);
2379:                    }
2380:                }
2381:            }
2382:
2383:            private void createPreparedStatementCaches() {
2384:                int cacheSize = getPreparedStatementCacheSize();
2385:
2386:                this .cachedPreparedStatementParams = new HashMap(cacheSize);
2387:
2388:                this .serverSideStatementCheckCache = new LRUCache(cacheSize);
2389:
2390:                this .serverSideStatementCache = new LRUCache(cacheSize) {
2391:                    protected boolean removeEldestEntry(
2392:                            java.util.Map.Entry eldest) {
2393:                        if (this .maxElements <= 1) {
2394:                            return false;
2395:                        }
2396:
2397:                        boolean removeIt = super .removeEldestEntry(eldest);
2398:
2399:                        if (removeIt) {
2400:                            ServerPreparedStatement ps = (ServerPreparedStatement) eldest
2401:                                    .getValue();
2402:                            ps.isCached = false;
2403:                            ps.setClosed(false);
2404:
2405:                            try {
2406:                                ps.close();
2407:                            } catch (SQLException sqlEx) {
2408:                                // punt
2409:                            }
2410:                        }
2411:
2412:                        return removeIt;
2413:                    }
2414:                };
2415:            }
2416:
2417:            /**
2418:             * SQL statements without parameters are normally executed using Statement
2419:             * objects. If the same SQL statement is executed many times, it is more
2420:             * efficient to use a PreparedStatement
2421:             * 
2422:             * @return a new Statement object
2423:             * @throws SQLException
2424:             *             passed through from the constructor
2425:             */
2426:            public java.sql.Statement createStatement() throws SQLException {
2427:                return createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
2428:                        java.sql.ResultSet.CONCUR_READ_ONLY);
2429:            }
2430:
2431:            /**
2432:             * JDBC 2.0 Same as createStatement() above, but allows the default result
2433:             * set type and result set concurrency type to be overridden.
2434:             * 
2435:             * @param resultSetType
2436:             *            a result set type, see ResultSet.TYPE_XXX
2437:             * @param resultSetConcurrency
2438:             *            a concurrency type, see ResultSet.CONCUR_XXX
2439:             * @return a new Statement object
2440:             * @exception SQLException
2441:             *                if a database-access error occurs.
2442:             */
2443:            public java.sql.Statement createStatement(int resultSetType,
2444:                    int resultSetConcurrency) throws SQLException {
2445:                checkClosed();
2446:
2447:                StatementImpl stmt = new com.mysql.jdbc.StatementImpl(this ,
2448:                        this .database);
2449:                stmt.setResultSetType(resultSetType);
2450:                stmt.setResultSetConcurrency(resultSetConcurrency);
2451:
2452:                return stmt;
2453:            }
2454:
2455:            /**
2456:             * @see Connection#createStatement(int, int, int)
2457:             */
2458:            public java.sql.Statement createStatement(int resultSetType,
2459:                    int resultSetConcurrency, int resultSetHoldability)
2460:                    throws SQLException {
2461:                if (getPedantic()) {
2462:                    if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
2463:                        throw SQLError
2464:                                .createSQLException(
2465:                                        "HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
2466:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2467:                    }
2468:                }
2469:
2470:                return createStatement(resultSetType, resultSetConcurrency);
2471:            }
2472:
2473:            protected void dumpTestcaseQuery(String query) {
2474:                System.err.println(query);
2475:            }
2476:
2477:            protected Connection duplicate() throws SQLException {
2478:                return new ConnectionImpl(this .origHostToConnectTo,
2479:                        this .origPortToConnectTo, this .props,
2480:                        this .origDatabaseToConnectTo, this .myURL);
2481:            }
2482:
2483:            /**
2484:             * Send a query to the server. Returns one of the ResultSet objects. This is
2485:             * synchronized, so Statement's queries will be serialized.
2486:             * 
2487:             * @param callingStatement
2488:             *            DOCUMENT ME!
2489:             * @param sql
2490:             *            the SQL statement to be executed
2491:             * @param maxRows
2492:             *            DOCUMENT ME!
2493:             * @param packet
2494:             *            DOCUMENT ME!
2495:             * @param resultSetType
2496:             *            DOCUMENT ME!
2497:             * @param resultSetConcurrency
2498:             *            DOCUMENT ME!
2499:             * @param streamResults
2500:             *            DOCUMENT ME!
2501:             * @param queryIsSelectOnly
2502:             *            DOCUMENT ME!
2503:             * @param catalog
2504:             *            DOCUMENT ME!
2505:             * @param unpackFields
2506:             *            DOCUMENT ME!
2507:             * @return a ResultSet holding the results
2508:             * @exception SQLException
2509:             *                if a database error occurs
2510:             */
2511:
2512:            // ResultSet execSQL(Statement callingStatement, String sql,
2513:            // int maxRowsToRetreive, String catalog) throws SQLException {
2514:            // return execSQL(callingStatement, sql, maxRowsToRetreive, null,
2515:            // java.sql.ResultSet.TYPE_FORWARD_ONLY,
2516:            // java.sql.ResultSet.CONCUR_READ_ONLY, catalog);
2517:            // }
2518:            // ResultSet execSQL(Statement callingStatement, String sql, int maxRows,
2519:            // int resultSetType, int resultSetConcurrency, boolean streamResults,
2520:            // boolean queryIsSelectOnly, String catalog, boolean unpackFields) throws
2521:            // SQLException {
2522:            // return execSQL(callingStatement, sql, maxRows, null, resultSetType,
2523:            // resultSetConcurrency, streamResults, queryIsSelectOnly, catalog,
2524:            // unpackFields);
2525:            // }
2526:            ResultSetInternalMethods execSQL(StatementImpl callingStatement,
2527:                    String sql, int maxRows, Buffer packet, int resultSetType,
2528:                    int resultSetConcurrency, boolean streamResults,
2529:                    String catalog, Field[] cachedMetadata) throws SQLException {
2530:                return execSQL(callingStatement, sql, maxRows, packet,
2531:                        resultSetType, resultSetConcurrency, streamResults,
2532:                        catalog, cachedMetadata, false);
2533:            }
2534:
2535:            ResultSetInternalMethods execSQL(StatementImpl callingStatement,
2536:                    String sql, int maxRows, Buffer packet, int resultSetType,
2537:                    int resultSetConcurrency, boolean streamResults,
2538:                    String catalog, Field[] cachedMetadata, boolean isBatch)
2539:                    throws SQLException {
2540:                //
2541:                // Fall-back if the master is back online if we've
2542:                // issued queriesBeforeRetryMaster queries since
2543:                // we failed over
2544:                //
2545:                synchronized (this .mutex) {
2546:                    long queryStartTime = 0;
2547:
2548:                    int endOfQueryPacketPosition = 0;
2549:
2550:                    if (packet != null) {
2551:                        endOfQueryPacketPosition = packet.getPosition();
2552:                    }
2553:
2554:                    if (getGatherPerformanceMetrics()) {
2555:                        queryStartTime = System.currentTimeMillis();
2556:                    }
2557:
2558:                    this .lastQueryFinishedTime = 0; // we're busy!
2559:
2560:                    if (this .failedOver && this .autoCommit && !isBatch) {
2561:                        if (shouldFallBack()
2562:                                && !this .executingFailoverReconnect) {
2563:                            try {
2564:                                this .executingFailoverReconnect = true;
2565:
2566:                                createNewIO(true);
2567:
2568:                                String connectedHost = this .io.getHost();
2569:
2570:                                if ((connectedHost != null)
2571:                                        && this .hostList.get(0).equals(
2572:                                                connectedHost)) {
2573:                                    this .failedOver = false;
2574:                                    this .queriesIssuedFailedOver = 0;
2575:                                    setReadOnlyInternal(false);
2576:                                }
2577:                            } finally {
2578:                                this .executingFailoverReconnect = false;
2579:                            }
2580:                        }
2581:                    }
2582:
2583:                    if ((getHighAvailability() || this .failedOver)
2584:                            && (this .autoCommit || getAutoReconnectForPools())
2585:                            && this .needsPing && !isBatch) {
2586:                        try {
2587:                            pingInternal(false);
2588:
2589:                            this .needsPing = false;
2590:                        } catch (Exception Ex) {
2591:                            createNewIO(true);
2592:                        }
2593:                    }
2594:
2595:                    try {
2596:                        if (packet == null) {
2597:                            String encoding = null;
2598:
2599:                            if (getUseUnicode()) {
2600:                                encoding = getEncoding();
2601:                            }
2602:
2603:                            return this .io.sqlQueryDirect(callingStatement,
2604:                                    sql, encoding, null, maxRows,
2605:                                    resultSetType, resultSetConcurrency,
2606:                                    streamResults, catalog, cachedMetadata);
2607:                        }
2608:
2609:                        return this .io.sqlQueryDirect(callingStatement, null,
2610:                                null, packet, maxRows, resultSetType,
2611:                                resultSetConcurrency, streamResults, catalog,
2612:                                cachedMetadata);
2613:                    } catch (java.sql.SQLException sqlE) {
2614:                        // don't clobber SQL exceptions
2615:
2616:                        if (getDumpQueriesOnException()) {
2617:                            String extractedSql = extractSqlFromPacket(sql,
2618:                                    packet, endOfQueryPacketPosition);
2619:                            StringBuffer messageBuf = new StringBuffer(
2620:                                    extractedSql.length() + 32);
2621:                            messageBuf
2622:                                    .append("\n\nQuery being executed when exception was thrown:\n\n");
2623:                            messageBuf.append(extractedSql);
2624:
2625:                            sqlE = appendMessageToException(sqlE, messageBuf
2626:                                    .toString());
2627:                        }
2628:
2629:                        if ((getHighAvailability() || this .failedOver)) {
2630:                            this .needsPing = true;
2631:                        } else {
2632:                            String sqlState = sqlE.getSQLState();
2633:
2634:                            if ((sqlState != null)
2635:                                    && sqlState
2636:                                            .equals(SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)) {
2637:                                cleanup(sqlE);
2638:                            }
2639:                        }
2640:
2641:                        throw sqlE;
2642:                    } catch (Exception ex) {
2643:                        if ((getHighAvailability() || this .failedOver)) {
2644:                            this .needsPing = true;
2645:                        } else if (ex instanceof  IOException) {
2646:                            cleanup(ex);
2647:                        }
2648:
2649:                        String exceptionType = ex.getClass().getName();
2650:                        String exceptionMessage = ex.getMessage();
2651:
2652:                        if (!getParanoid()) {
2653:                            exceptionMessage += "\n\nNested Stack Trace:\n";
2654:                            exceptionMessage += Util.stackTraceToString(ex);
2655:                        }
2656:
2657:                        throw new java.sql.SQLException(
2658:                                "Error during query: Unexpected Exception: "
2659:                                        + exceptionType + " message given: "
2660:                                        + exceptionMessage,
2661:                                SQLError.SQL_STATE_GENERAL_ERROR);
2662:                    } finally {
2663:                        if (getMaintainTimeStats()) {
2664:                            this .lastQueryFinishedTime = System
2665:                                    .currentTimeMillis();
2666:                        }
2667:
2668:                        if (this .failedOver) {
2669:                            this .queriesIssuedFailedOver++;
2670:                        }
2671:
2672:                        if (getGatherPerformanceMetrics()) {
2673:                            long queryTime = System.currentTimeMillis()
2674:                                    - queryStartTime;
2675:
2676:                            registerQueryExecutionTime(queryTime);
2677:                        }
2678:                    }
2679:                }
2680:            }
2681:
2682:            protected String extractSqlFromPacket(String possibleSqlQuery,
2683:                    Buffer queryPacket, int endOfQueryPacketPosition)
2684:                    throws SQLException {
2685:
2686:                String extractedSql = null;
2687:
2688:                if (possibleSqlQuery != null) {
2689:                    if (possibleSqlQuery.length() > getMaxQuerySizeToLog()) {
2690:                        StringBuffer truncatedQueryBuf = new StringBuffer(
2691:                                possibleSqlQuery.substring(0,
2692:                                        getMaxQuerySizeToLog()));
2693:                        truncatedQueryBuf.append(Messages
2694:                                .getString("MysqlIO.25"));
2695:                        extractedSql = truncatedQueryBuf.toString();
2696:                    } else {
2697:                        extractedSql = possibleSqlQuery;
2698:                    }
2699:                }
2700:
2701:                if (extractedSql == null) {
2702:                    // This is probably from a client-side prepared
2703:                    // statement
2704:
2705:                    int extractPosition = endOfQueryPacketPosition;
2706:
2707:                    boolean truncated = false;
2708:
2709:                    if (endOfQueryPacketPosition > getMaxQuerySizeToLog()) {
2710:                        extractPosition = getMaxQuerySizeToLog();
2711:                        truncated = true;
2712:                    }
2713:
2714:                    extractedSql = new String(queryPacket.getByteBuffer(), 5,
2715:                            (extractPosition - 5));
2716:
2717:                    if (truncated) {
2718:                        extractedSql += Messages.getString("MysqlIO.25"); //$NON-NLS-1$
2719:                    }
2720:                }
2721:
2722:                return extractedSql;
2723:
2724:            }
2725:
2726:            /**
2727:             * DOCUMENT ME!
2728:             * 
2729:             * @throws Throwable
2730:             *             DOCUMENT ME!
2731:             */
2732:            protected void finalize() throws Throwable {
2733:                cleanup(null);
2734:
2735:                super .finalize();
2736:            }
2737:
2738:            protected StringBuffer generateConnectionCommentBlock(
2739:                    StringBuffer buf) {
2740:                buf.append("/* conn id ");
2741:                buf.append(getId());
2742:                buf.append(" */ ");
2743:
2744:                return buf;
2745:            }
2746:
2747:            public int getActiveStatementCount() {
2748:                // Might not have one of these if
2749:                // not tracking open resources
2750:                if (this .openStatements != null) {
2751:                    synchronized (this .openStatements) {
2752:                        return this .openStatements.size();
2753:                    }
2754:                }
2755:
2756:                return 0;
2757:            }
2758:
2759:            /**
2760:             * Gets the current auto-commit state
2761:             * 
2762:             * @return Current state of auto-commit
2763:             * @exception SQLException
2764:             *                if an error occurs
2765:             * @see setAutoCommit
2766:             */
2767:            public boolean getAutoCommit() throws SQLException {
2768:                return this .autoCommit;
2769:            }
2770:
2771:            /**
2772:             * Optimization to only use one calendar per-session, or calculate it for
2773:             * each call, depending on user configuration
2774:             */
2775:            protected Calendar getCalendarInstanceForSessionOrNew() {
2776:                if (getDynamicCalendars()) {
2777:                    return Calendar.getInstance();
2778:                }
2779:
2780:                return getSessionLockedCalendar();
2781:            }
2782:
2783:            /**
2784:             * Return the connections current catalog name, or null if no catalog name
2785:             * is set, or we dont support catalogs.
2786:             * <p>
2787:             * <b>Note:</b> MySQL's notion of catalogs are individual databases.
2788:             * </p>
2789:             * 
2790:             * @return the current catalog name or null
2791:             * @exception SQLException
2792:             *                if a database access error occurs
2793:             */
2794:            public String getCatalog() throws SQLException {
2795:                return this .database;
2796:            }
2797:
2798:            /**
2799:             * @return Returns the characterSetMetadata.
2800:             */
2801:            protected String getCharacterSetMetadata() {
2802:                return characterSetMetadata;
2803:            }
2804:
2805:            /**
2806:             * Returns the locally mapped instance of a charset converter (to avoid
2807:             * overhead of static synchronization).
2808:             * 
2809:             * @param javaEncodingName
2810:             *            the encoding name to retrieve
2811:             * @return a character converter, or null if one couldn't be mapped.
2812:             */
2813:            SingleByteCharsetConverter getCharsetConverter(
2814:                    String javaEncodingName) throws SQLException {
2815:                if (javaEncodingName == null) {
2816:                    return null;
2817:                }
2818:
2819:                if (this .usePlatformCharsetConverters) {
2820:                    return null; // we'll use Java's built-in routines for this
2821:                    // they're finally fast enough
2822:                }
2823:
2824:                SingleByteCharsetConverter converter = null;
2825:
2826:                synchronized (this .charsetConverterMap) {
2827:                    Object asObject = this .charsetConverterMap
2828:                            .get(javaEncodingName);
2829:
2830:                    if (asObject == CHARSET_CONVERTER_NOT_AVAILABLE_MARKER) {
2831:                        return null;
2832:                    }
2833:
2834:                    converter = (SingleByteCharsetConverter) asObject;
2835:
2836:                    if (converter == null) {
2837:                        try {
2838:                            converter = SingleByteCharsetConverter.getInstance(
2839:                                    javaEncodingName, this );
2840:
2841:                            if (converter == null) {
2842:                                this .charsetConverterMap.put(javaEncodingName,
2843:                                        CHARSET_CONVERTER_NOT_AVAILABLE_MARKER);
2844:                            } else {
2845:                                this .charsetConverterMap.put(javaEncodingName,
2846:                                        converter);
2847:                            }
2848:                        } catch (UnsupportedEncodingException unsupEncEx) {
2849:                            this .charsetConverterMap.put(javaEncodingName,
2850:                                    CHARSET_CONVERTER_NOT_AVAILABLE_MARKER);
2851:
2852:                            converter = null;
2853:                        }
2854:                    }
2855:                }
2856:
2857:                return converter;
2858:            }
2859:
2860:            /**
2861:             * Returns the Java character encoding name for the given MySQL server
2862:             * charset index
2863:             * 
2864:             * @param charsetIndex
2865:             * @return the Java character encoding name for the given MySQL server
2866:             *         charset index
2867:             * @throws SQLException
2868:             *             if the character set index isn't known by the driver
2869:             */
2870:            protected String getCharsetNameForIndex(int charsetIndex)
2871:                    throws SQLException {
2872:                String charsetName = null;
2873:
2874:                if (getUseOldUTF8Behavior()) {
2875:                    return getEncoding();
2876:                }
2877:
2878:                if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) {
2879:                    try {
2880:                        charsetName = this .indexToCharsetMapping[charsetIndex];
2881:
2882:                        if ("sjis".equalsIgnoreCase(charsetName)
2883:                                || "MS932".equalsIgnoreCase(charsetName) /* for JDK6 */) {
2884:                            // Use our encoding so that code pages like Cp932 work
2885:                            if (CharsetMapping.isAliasForSjis(getEncoding())) {
2886:                                charsetName = getEncoding();
2887:                            }
2888:                        }
2889:                    } catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
2890:                        throw SQLError.createSQLException(
2891:                                "Unknown character set index for field '"
2892:                                        + charsetIndex
2893:                                        + "' received from server.",
2894:                                SQLError.SQL_STATE_GENERAL_ERROR);
2895:                    }
2896:
2897:                    // Punt
2898:                    if (charsetName == null) {
2899:                        charsetName = getEncoding();
2900:                    }
2901:                } else {
2902:                    charsetName = getEncoding();
2903:                }
2904:
2905:                return charsetName;
2906:            }
2907:
2908:            /**
2909:             * DOCUMENT ME!
2910:             * 
2911:             * @return Returns the defaultTimeZone.
2912:             */
2913:            protected TimeZone getDefaultTimeZone() {
2914:                return this .defaultTimeZone;
2915:            }
2916:
2917:            protected String getErrorMessageEncoding() {
2918:                return errorMessageEncoding;
2919:            }
2920:
2921:            /**
2922:             * @see Connection#getHoldability()
2923:             */
2924:            public int getHoldability() throws SQLException {
2925:                return java.sql.ResultSet.CLOSE_CURSORS_AT_COMMIT;
2926:            }
2927:
2928:            long getId() {
2929:                return this .connectionId;
2930:            }
2931:
2932:            /**
2933:             * NOT JDBC-Compliant, but clients can use this method to determine how long
2934:             * this connection has been idle. This time (reported in milliseconds) is
2935:             * updated once a query has completed.
2936:             * 
2937:             * @return number of ms that this connection has been idle, 0 if the driver
2938:             *         is busy retrieving results.
2939:             */
2940:            public long getIdleFor() {
2941:                if (this .lastQueryFinishedTime == 0) {
2942:                    return 0;
2943:                }
2944:
2945:                long now = System.currentTimeMillis();
2946:                long idleTime = now - this .lastQueryFinishedTime;
2947:
2948:                return idleTime;
2949:            }
2950:
2951:            /**
2952:             * Returns the IO channel to the server
2953:             * 
2954:             * @return the IO channel to the server
2955:             * @throws SQLException
2956:             *             if the connection is closed.
2957:             */
2958:            protected MysqlIO getIO() throws SQLException {
2959:                if ((this .io == null) || this .isClosed) {
2960:                    throw SQLError.createSQLException(
2961:                            "Operation not allowed on closed connection",
2962:                            SQLError.SQL_STATE_CONNECTION_NOT_OPEN);
2963:                }
2964:
2965:                return this .io;
2966:            }
2967:
2968:            /**
2969:             * Returns the log mechanism that should be used to log information from/for
2970:             * this Connection.
2971:             * 
2972:             * @return the Log instance to use for logging messages.
2973:             * @throws SQLException
2974:             *             if an error occurs
2975:             */
2976:            public Log getLog() throws SQLException {
2977:                return this .log;
2978:            }
2979:
2980:            /**
2981:             * Returns the maximum packet size the MySQL server will accept
2982:             * 
2983:             * @return DOCUMENT ME!
2984:             */
2985:            int getMaxAllowedPacket() {
2986:                return this .maxAllowedPacket;
2987:            }
2988:
2989:            protected int getMaxBytesPerChar(String javaCharsetName)
2990:                    throws SQLException {
2991:                // TODO: Check if we can actually run this query at this point in time
2992:                String charset = CharsetMapping
2993:                        .getMysqlEncodingForJavaEncoding(javaCharsetName, this );
2994:
2995:                if (versionMeetsMinimum(4, 1, 0)) {
2996:                    Map mapToCheck = null;
2997:
2998:                    if (!getUseDynamicCharsetInfo()) {
2999:                        mapToCheck = CharsetMapping.STATIC_CHARSET_TO_NUM_BYTES_MAP;
3000:                    } else {
3001:                        mapToCheck = this .charsetToNumBytesMap;
3002:
3003:                        synchronized (this .charsetToNumBytesMap) {
3004:                            if (this .charsetToNumBytesMap.isEmpty()) {
3005:
3006:                                java.sql.Statement stmt = null;
3007:                                java.sql.ResultSet rs = null;
3008:
3009:                                try {
3010:                                    stmt = getMetadataSafeStatement();
3011:
3012:                                    rs = stmt
3013:                                            .executeQuery("SHOW CHARACTER SET");
3014:
3015:                                    while (rs.next()) {
3016:                                        this .charsetToNumBytesMap.put(rs
3017:                                                .getString("Charset"),
3018:                                                Constants.integerValueOf(rs
3019:                                                        .getInt("Maxlen")));
3020:                                    }
3021:
3022:                                    rs.close();
3023:                                    rs = null;
3024:
3025:                                    stmt.close();
3026:
3027:                                    stmt = null;
3028:                                } finally {
3029:                                    if (rs != null) {
3030:                                        rs.close();
3031:                                        rs = null;
3032:                                    }
3033:
3034:                                    if (stmt != null) {
3035:                                        stmt.close();
3036:                                        stmt = null;
3037:                                    }
3038:                                }
3039:                            }
3040:                        }
3041:                    }
3042:
3043:                    Integer mbPerChar = (Integer) mapToCheck.get(charset);
3044:
3045:                    if (mbPerChar != null) {
3046:                        return mbPerChar.intValue();
3047:                    }
3048:
3049:                    return 1; // we don't know
3050:                }
3051:
3052:                return 1; // we don't know
3053:            }
3054:
3055:            /**
3056:             * A connection's database is able to provide information describing its
3057:             * tables, its supported SQL grammar, its stored procedures, the
3058:             * capabilities of this connection, etc. This information is made available
3059:             * through a DatabaseMetaData object.
3060:             * 
3061:             * @return a DatabaseMetaData object for this connection
3062:             * @exception SQLException
3063:             *                if a database access error occurs
3064:             */
3065:            public java.sql.DatabaseMetaData getMetaData() throws SQLException {
3066:                checkClosed();
3067:                return com.mysql.jdbc.DatabaseMetaData.getInstance(this ,
3068:                        this .database);
3069:            }
3070:
3071:            protected java.sql.Statement getMetadataSafeStatement()
3072:                    throws SQLException {
3073:                java.sql.Statement stmt = createStatement();
3074:
3075:                if (stmt.getMaxRows() != 0) {
3076:                    stmt.setMaxRows(0);
3077:                }
3078:
3079:                stmt.setEscapeProcessing(false);
3080:
3081:                return stmt;
3082:            }
3083:
3084:            /**
3085:             * Returns the Mutex all queries are locked against
3086:             * 
3087:             * @return DOCUMENT ME!
3088:             * @throws SQLException
3089:             *             DOCUMENT ME!
3090:             */
3091:            Object getMutex() throws SQLException {
3092:                if (this .io == null) {
3093:                    throw SQLError
3094:                            .createSQLException(
3095:                                    "Connection.close() has already been called. Invalid operation in this state.",
3096:                                    SQLError.SQL_STATE_CONNECTION_NOT_OPEN);
3097:                }
3098:
3099:                reportMetricsIfNeeded();
3100:
3101:                return this .mutex;
3102:            }
3103:
3104:            /**
3105:             * Returns the packet buffer size the MySQL server reported upon connection
3106:             * 
3107:             * @return DOCUMENT ME!
3108:             */
3109:            int getNetBufferLength() {
3110:                return this .netBufferLength;
3111:            }
3112:
3113:            /**
3114:             * Returns the server's character set
3115:             * 
3116:             * @return the server's character set.
3117:             */
3118:            public String getServerCharacterEncoding() {
3119:                if (this .io.versionMeetsMinimum(4, 1, 0)) {
3120:                    return (String) this .serverVariables
3121:                            .get("character_set_server");
3122:                } else {
3123:                    return (String) this .serverVariables.get("character_set");
3124:                }
3125:            }
3126:
3127:            int getServerMajorVersion() {
3128:                return this .io.getServerMajorVersion();
3129:            }
3130:
3131:            int getServerMinorVersion() {
3132:                return this .io.getServerMinorVersion();
3133:            }
3134:
3135:            int getServerSubMinorVersion() {
3136:                return this .io.getServerSubMinorVersion();
3137:            }
3138:
3139:            /**
3140:             * DOCUMENT ME!
3141:             * 
3142:             * @return DOCUMENT ME!
3143:             */
3144:            public TimeZone getServerTimezoneTZ() {
3145:                return this .serverTimezoneTZ;
3146:            }
3147:
3148:            String getServerVariable(String variableName) {
3149:                if (this .serverVariables != null) {
3150:                    return (String) this .serverVariables.get(variableName);
3151:                }
3152:
3153:                return null;
3154:            }
3155:
3156:            String getServerVersion() {
3157:                return this .io.getServerVersion();
3158:            }
3159:
3160:            protected Calendar getSessionLockedCalendar() {
3161:
3162:                return this .sessionCalendar;
3163:            }
3164:
3165:            /**
3166:             * Get this Connection's current transaction isolation mode.
3167:             * 
3168:             * @return the current TRANSACTION_ mode value
3169:             * @exception SQLException
3170:             *                if a database access error occurs
3171:             */
3172:            public int getTransactionIsolation() throws SQLException {
3173:
3174:                if (this .hasIsolationLevels && !getUseLocalSessionState()) {
3175:                    java.sql.Statement stmt = null;
3176:                    java.sql.ResultSet rs = null;
3177:
3178:                    try {
3179:                        stmt = getMetadataSafeStatement();
3180:
3181:                        String query = null;
3182:
3183:                        int offset = 0;
3184:
3185:                        if (versionMeetsMinimum(4, 0, 3)) {
3186:                            query = "SELECT @@session.tx_isolation";
3187:                            offset = 1;
3188:                        } else {
3189:                            query = "SHOW VARIABLES LIKE 'transaction_isolation'";
3190:                            offset = 2;
3191:                        }
3192:
3193:                        rs = stmt.executeQuery(query);
3194:
3195:                        if (rs.next()) {
3196:                            String s = rs.getString(offset);
3197:
3198:                            if (s != null) {
3199:                                Integer intTI = (Integer) mapTransIsolationNameToValue
3200:                                        .get(s);
3201:
3202:                                if (intTI != null) {
3203:                                    return intTI.intValue();
3204:                                }
3205:                            }
3206:
3207:                            throw SQLError.createSQLException(
3208:                                    "Could not map transaction isolation '" + s
3209:                                            + " to a valid JDBC level.",
3210:                                    SQLError.SQL_STATE_GENERAL_ERROR);
3211:                        }
3212:
3213:                        throw SQLError
3214:                                .createSQLException(
3215:                                        "Could not retrieve transaction isolation level from server",
3216:                                        SQLError.SQL_STATE_GENERAL_ERROR);
3217:
3218:                    } finally {
3219:                        if (rs != null) {
3220:                            try {
3221:                                rs.close();
3222:                            } catch (Exception ex) {
3223:                                // ignore
3224:                                ;
3225:                            }
3226:
3227:                            rs = null;
3228:                        }
3229:
3230:                        if (stmt != null) {
3231:                            try {
3232:                                stmt.close();
3233:                            } catch (Exception ex) {
3234:                                // ignore
3235:                                ;
3236:                            }
3237:
3238:                            stmt = null;
3239:                        }
3240:                    }
3241:                }
3242:
3243:                return this .isolationLevel;
3244:            }
3245:
3246:            /**
3247:             * JDBC 2.0 Get the type-map object associated with this connection. By
3248:             * default, the map returned is empty.
3249:             * 
3250:             * @return the type map
3251:             * @throws SQLException
3252:             *             if a database error occurs
3253:             */
3254:            public synchronized java.util.Map getTypeMap() throws SQLException {
3255:                if (this .typeMap == null) {
3256:                    this .typeMap = new HashMap();
3257:                }
3258:
3259:                return this .typeMap;
3260:            }
3261:
3262:            String getURL() {
3263:                return this .myURL;
3264:            }
3265:
3266:            String getUser() {
3267:                return this .user;
3268:            }
3269:
3270:            protected Calendar getUtcCalendar() {
3271:                return this .utcCalendar;
3272:            }
3273:
3274:            /**
3275:             * The first warning reported by calls on this Connection is returned.
3276:             * <B>Note:</B> Sebsequent warnings will be changed to this
3277:             * java.sql.SQLWarning
3278:             * 
3279:             * @return the first java.sql.SQLWarning or null
3280:             * @exception SQLException
3281:             *                if a database access error occurs
3282:             */
3283:            public SQLWarning getWarnings() throws SQLException {
3284:                return null;
3285:            }
3286:
3287:            public boolean hasSameProperties(Connection c) {
3288:                return this .props.equals(((ConnectionImpl) c).props);
3289:            }
3290:
3291:            public boolean hasTriedMaster() {
3292:                return this .hasTriedMasterFlag;
3293:            }
3294:
3295:            protected void incrementNumberOfPreparedExecutes() {
3296:                if (getGatherPerformanceMetrics()) {
3297:                    this .numberOfPreparedExecutes++;
3298:
3299:                    // We need to increment this, because
3300:                    // server-side prepared statements bypass
3301:                    // any execution by the connection itself...
3302:                    this .numberOfQueriesIssued++;
3303:                }
3304:            }
3305:
3306:            protected void incrementNumberOfPrepares() {
3307:                if (getGatherPerformanceMetrics()) {
3308:                    this .numberOfPrepares++;
3309:                }
3310:            }
3311:
3312:            protected void incrementNumberOfResultSetsCreated() {
3313:                if (getGatherPerformanceMetrics()) {
3314:                    this .numberOfResultSetsCreated++;
3315:                }
3316:            }
3317:
3318:            /**
3319:             * Initializes driver properties that come from URL or properties passed to
3320:             * the driver manager.
3321:             * 
3322:             * @param info
3323:             *            DOCUMENT ME!
3324:             * @throws SQLException
3325:             *             DOCUMENT ME!
3326:             */
3327:            private void initializeDriverProperties(Properties info)
3328:                    throws SQLException {
3329:                initializeProperties(info);
3330:
3331:                this .usePlatformCharsetConverters = getUseJvmCharsetConverters();
3332:
3333:                this .log = LogFactory.getLogger(getLogger(),
3334:                        LOGGER_INSTANCE_NAME);
3335:
3336:                if (getProfileSql() || getUseUsageAdvisor()) {
3337:                    this .eventSink = ProfileEventSink.getInstance(this );
3338:                }
3339:
3340:                if (getCachePreparedStatements()) {
3341:                    createPreparedStatementCaches();
3342:                }
3343:
3344:                if (getNoDatetimeStringSync() && getUseTimezone()) {
3345:                    throw SQLError.createSQLException(
3346:                            "Can't enable noDatetimeSync and useTimezone configuration "
3347:                                    + "properties at the same time",
3348:                            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3349:                }
3350:
3351:                if (getCacheCallableStatements()) {
3352:                    this .parsedCallableStatementCache = new LRUCache(
3353:                            getCallableStatementCacheSize());
3354:                }
3355:
3356:                if (getAllowMultiQueries()) {
3357:                    setCacheResultSetMetadata(false); // we don't handle this yet
3358:                }
3359:
3360:                if (getCacheResultSetMetadata()) {
3361:                    this .resultSetMetadataCache = new LRUCache(
3362:                            getMetadataCacheSize());
3363:                }
3364:            }
3365:
3366:            /**
3367:             * Sets varying properties that depend on server information. Called once we
3368:             * have connected to the server.
3369:             * 
3370:             * @param info
3371:             *            DOCUMENT ME!
3372:             * @throws SQLException
3373:             *             DOCUMENT ME!
3374:             */
3375:            private void initializePropsFromServer() throws SQLException {
3376:                setSessionVariables();
3377:
3378:                //
3379:                // the "boolean" type didn't come along until MySQL-4.1
3380:                //
3381:
3382:                if (!versionMeetsMinimum(4, 1, 0)) {
3383:                    setTransformedBitIsBoolean(false);
3384:                }
3385:
3386:                this .parserKnowsUnicode = versionMeetsMinimum(4, 1, 0);
3387:
3388:                //
3389:                // Users can turn off detection of server-side prepared statements
3390:                //
3391:                if (getUseServerPreparedStmts() && versionMeetsMinimum(4, 1, 0)) {
3392:                    this .useServerPreparedStmts = true;
3393:
3394:                    if (versionMeetsMinimum(5, 0, 0)
3395:                            && !versionMeetsMinimum(5, 0, 3)) {
3396:                        this .useServerPreparedStmts = false; // 4.1.2+ style prepared
3397:                        // statements
3398:                        // don't work on these versions
3399:                    }
3400:                }
3401:
3402:                this .serverVariables.clear();
3403:
3404:                //
3405:                // If version is greater than 3.21.22 get the server
3406:                // variables.
3407:                if (versionMeetsMinimum(3, 21, 22)) {
3408:                    loadServerVariables();
3409:
3410:                    buildCollationMapping();
3411:
3412:                    LicenseConfiguration.checkLicenseType(this .serverVariables);
3413:
3414:                    String lowerCaseTables = (String) this .serverVariables
3415:                            .get("lower_case_table_names");
3416:
3417:                    this .lowerCaseTableNames = "on"
3418:                            .equalsIgnoreCase(lowerCaseTables)
3419:                            || "1".equalsIgnoreCase(lowerCaseTables)
3420:                            || "2".equalsIgnoreCase(lowerCaseTables);
3421:
3422:                    configureTimezone();
3423:
3424:                    if (this .serverVariables.containsKey("max_allowed_packet")) {
3425:                        this .maxAllowedPacket = Integer
3426:                                .parseInt((String) this .serverVariables
3427:                                        .get("max_allowed_packet"));
3428:
3429:                        int preferredBlobSendChunkSize = getBlobSendChunkSize();
3430:
3431:                        int allowedBlobSendChunkSize = Math.min(
3432:                                preferredBlobSendChunkSize,
3433:                                this .maxAllowedPacket)
3434:                                - ServerPreparedStatement.BLOB_STREAM_READ_BUF_SIZE
3435:                                - 11 /* LONG_DATA and MySQLIO packet header size */;
3436:
3437:                        setBlobSendChunkSize(String
3438:                                .valueOf(allowedBlobSendChunkSize));
3439:                    }
3440:
3441:                    if (this .serverVariables.containsKey("net_buffer_length")) {
3442:                        this .netBufferLength = Integer
3443:                                .parseInt((String) this .serverVariables
3444:                                        .get("net_buffer_length"));
3445:                    }
3446:
3447:                    checkTransactionIsolationLevel();
3448:
3449:                    if (!versionMeetsMinimum(4, 1, 0)) {
3450:                        checkServerEncoding();
3451:                    }
3452:
3453:                    this .io.checkForCharsetMismatch();
3454:
3455:                    if (this .serverVariables.containsKey("sql_mode")) {
3456:                        int sqlMode = 0;
3457:
3458:                        String sqlModeAsString = (String) this .serverVariables
3459:                                .get("sql_mode");
3460:                        try {
3461:                            sqlMode = Integer.parseInt(sqlModeAsString);
3462:                        } catch (NumberFormatException nfe) {
3463:                            // newer versions of the server has this as a string-y
3464:                            // list...
3465:                            sqlMode = 0;
3466:
3467:                            if (sqlModeAsString != null) {
3468:                                if (sqlModeAsString.indexOf("ANSI_QUOTES") != -1) {
3469:                                    sqlMode |= 4;
3470:                                }
3471:
3472:                                if (sqlModeAsString
3473:                                        .indexOf("NO_BACKSLASH_ESCAPES") != -1) {
3474:                                    this .noBackslashEscapes = true;
3475:                                }
3476:                            }
3477:                        }
3478:
3479:                        if ((sqlMode & 4) > 0) {
3480:                            this .useAnsiQuotes = true;
3481:                        } else {
3482:                            this .useAnsiQuotes = false;
3483:                        }
3484:                    }
3485:                }
3486:
3487:                this .errorMessageEncoding = CharsetMapping
3488:                        .getCharacterEncodingForErrorMessages(this );
3489:
3490:                boolean overrideDefaultAutocommit = isAutoCommitNonDefaultOnServer();
3491:
3492:                configureClientCharacterSet(false);
3493:
3494:                if (versionMeetsMinimum(3, 23, 15)) {
3495:                    this .transactionsSupported = true;
3496:
3497:                    if (!overrideDefaultAutocommit) {
3498:                        setAutoCommit(true); // to override anything
3499:                        // the server is set to...reqd
3500:                        // by JDBC spec.
3501:                    }
3502:                } else {
3503:                    this .transactionsSupported = false;
3504:                }
3505:
3506:                if (versionMeetsMinimum(3, 23, 36)) {
3507:                    this .hasIsolationLevels = true;
3508:                } else {
3509:                    this .hasIsolationLevels = false;
3510:                }
3511:
3512:                this .hasQuotedIdentifiers = versionMeetsMinimum(3, 23, 6);
3513:
3514:                this .io.resetMaxBuf();
3515:
3516:                //
3517:                // If we're using MySQL 4.1.0 or newer, we need to figure
3518:                // out what character set metadata will be returned in,
3519:                // and then map that to a Java encoding name.
3520:                //
3521:                // We've already set it, and it might be different than what
3522:                // was originally on the server, which is why we use the
3523:                // "special" key to retrieve it
3524:                if (this .io.versionMeetsMinimum(4, 1, 0)) {
3525:                    String characterSetResultsOnServerMysql = (String) this .serverVariables
3526:                            .get(JDBC_LOCAL_CHARACTER_SET_RESULTS);
3527:
3528:                    if (characterSetResultsOnServerMysql == null
3529:                            || StringUtils.startsWithIgnoreCaseAndWs(
3530:                                    characterSetResultsOnServerMysql, "NULL")
3531:                            || characterSetResultsOnServerMysql.length() == 0) {
3532:                        String defaultMetadataCharsetMysql = (String) this .serverVariables
3533:                                .get("character_set_system");
3534:                        String defaultMetadataCharset = null;
3535:
3536:                        if (defaultMetadataCharsetMysql != null) {
3537:                            defaultMetadataCharset = CharsetMapping
3538:                                    .getJavaEncodingForMysqlEncoding(
3539:                                            defaultMetadataCharsetMysql, this );
3540:                        } else {
3541:                            defaultMetadataCharset = "UTF-8";
3542:                        }
3543:
3544:                        this .characterSetMetadata = defaultMetadataCharset;
3545:                    } else {
3546:                        this .characterSetResultsOnServer = CharsetMapping
3547:                                .getJavaEncodingForMysqlEncoding(
3548:                                        characterSetResultsOnServerMysql, this );
3549:                        this .characterSetMetadata = this .characterSetResultsOnServer;
3550:                    }
3551:                }
3552:
3553:                //
3554:                // Query cache is broken wrt. multi-statements before MySQL-4.1.10
3555:                //
3556:
3557:                if (this .versionMeetsMinimum(4, 1, 0)
3558:                        && !this .versionMeetsMinimum(4, 1, 10)
3559:                        && getAllowMultiQueries()) {
3560:                    if ("ON".equalsIgnoreCase((String) this .serverVariables
3561:                            .get("query_cache_type"))
3562:                            && !"0"
3563:                                    .equalsIgnoreCase((String) this .serverVariables
3564:                                            .get("query_cache_size"))) {
3565:                        setAllowMultiQueries(false);
3566:                    }
3567:                }
3568:
3569:                //
3570:                // Server can do this more efficiently for us
3571:                //
3572:
3573:                setupServerForTruncationChecks();
3574:            }
3575:
3576:            /**
3577:             * Has the default autocommit value of 0 been changed on the server
3578:             * via init_connect?
3579:             * 
3580:             * @return true if autocommit is not the default of '0' on the server.
3581:             * 
3582:             * @throws SQLException
3583:             */
3584:            private boolean isAutoCommitNonDefaultOnServer()
3585:                    throws SQLException {
3586:                boolean overrideDefaultAutocommit = false;
3587:
3588:                String initConnectValue = (String) this .serverVariables
3589:                        .get("init_connect");
3590:
3591:                if (versionMeetsMinimum(4, 1, 2) && initConnectValue != null
3592:                        && initConnectValue.length() > 0) {
3593:                    if (!getElideSetAutoCommits()) {
3594:                        // auto-commit might have changed
3595:                        java.sql.ResultSet rs = null;
3596:                        java.sql.Statement stmt = null;
3597:
3598:                        try {
3599:                            stmt = getMetadataSafeStatement();
3600:
3601:                            rs = stmt
3602:                                    .executeQuery("SELECT @@session.autocommit");
3603:
3604:                            if (rs.next()) {
3605:                                this .autoCommit = rs.getBoolean(1);
3606:                                if (this .autoCommit != true) {
3607:                                    overrideDefaultAutocommit = true;
3608:                                }
3609:                            }
3610:
3611:                        } finally {
3612:                            if (rs != null) {
3613:                                try {
3614:                                    rs.close();
3615:                                } catch (SQLException sqlEx) {
3616:                                    // do nothing
3617:                                }
3618:                            }
3619:
3620:                            if (stmt != null) {
3621:                                try {
3622:                                    stmt.close();
3623:                                } catch (SQLException sqlEx) {
3624:                                    // do nothing
3625:                                }
3626:                            }
3627:                        }
3628:                    } else {
3629:                        if (this .getIO().isSetNeededForAutoCommitMode(true)) {
3630:                            // we're not in standard autocommit=true mode
3631:                            this .autoCommit = false;
3632:                            overrideDefaultAutocommit = true;
3633:                        }
3634:                    }
3635:                }
3636:
3637:                return overrideDefaultAutocommit;
3638:            }
3639:
3640:            protected boolean isClientTzUTC() {
3641:                return this .isClientTzUTC;
3642:            }
3643:
3644:            /**
3645:             * DOCUMENT ME!
3646:             * 
3647:             * @return DOCUMENT ME!
3648:             */
3649:            public boolean isClosed() {
3650:                return this .isClosed;
3651:            }
3652:
3653:            protected boolean isCursorFetchEnabled() throws SQLException {
3654:                return (versionMeetsMinimum(5, 0, 2) && getUseCursorFetch());
3655:            }
3656:
3657:            public boolean isInGlobalTx() {
3658:                return this .isInGlobalTx;
3659:            }
3660:
3661:            /**
3662:             * Is this connection connected to the first host in the list if
3663:             * there is a list of servers in the URL?
3664:             * 
3665:             * @return true if this connection is connected to the first in 
3666:             * the list.
3667:             */
3668:            public synchronized boolean isMasterConnection() {
3669:                return !this .failedOver;
3670:            }
3671:
3672:            /**
3673:             * Is the server in a sql_mode that doesn't allow us to use \\ to escape
3674:             * things?
3675:             * 
3676:             * @return Returns the noBackslashEscapes.
3677:             */
3678:            public boolean isNoBackslashEscapesSet() {
3679:                return this .noBackslashEscapes;
3680:            }
3681:
3682:            boolean isReadInfoMsgEnabled() {
3683:                return this .readInfoMsg;
3684:            }
3685:
3686:            /**
3687:             * Tests to see if the connection is in Read Only Mode. Note that we cannot
3688:             * really put the database in read only mode, but we pretend we can by
3689:             * returning the value of the readOnly flag
3690:             * 
3691:             * @return true if the connection is read only
3692:             * @exception SQLException
3693:             *                if a database access error occurs
3694:             */
3695:            public boolean isReadOnly() throws SQLException {
3696:                return this .readOnly;
3697:            }
3698:
3699:            protected boolean isRunningOnJDK13() {
3700:                return this .isRunningOnJDK13;
3701:            }
3702:
3703:            public synchronized boolean isSameResource(
3704:                    Connection otherConnection) {
3705:                if (otherConnection == null) {
3706:                    return false;
3707:                }
3708:
3709:                boolean directCompare = true;
3710:
3711:                String otherHost = ((ConnectionImpl) otherConnection).origHostToConnectTo;
3712:                String otherOrigDatabase = ((ConnectionImpl) otherConnection).origDatabaseToConnectTo;
3713:                String otherCurrentCatalog = ((ConnectionImpl) otherConnection).database;
3714:
3715:                if (!nullSafeCompare(otherHost, this .origHostToConnectTo)) {
3716:                    directCompare = false;
3717:                } else if (otherHost != null && otherHost.indexOf(',') == -1
3718:                        && otherHost.indexOf(':') == -1) {
3719:                    // need to check port numbers
3720:                    directCompare = (((ConnectionImpl) otherConnection).origPortToConnectTo == this .origPortToConnectTo);
3721:                }
3722:
3723:                if (directCompare) {
3724:                    if (!nullSafeCompare(otherOrigDatabase,
3725:                            this .origDatabaseToConnectTo)) {
3726:                        directCompare = false;
3727:                        directCompare = false;
3728:                    } else if (!nullSafeCompare(otherCurrentCatalog,
3729:                            this .database)) {
3730:                        directCompare = false;
3731:                    }
3732:                }
3733:
3734:                if (directCompare) {
3735:                    return true;
3736:                }
3737:
3738:                // Has the user explicitly set a resourceId?
3739:                String otherResourceId = ((ConnectionImpl) otherConnection)
3740:                        .getResourceId();
3741:                String myResourceId = getResourceId();
3742:
3743:                if (otherResourceId != null || myResourceId != null) {
3744:                    directCompare = nullSafeCompare(otherResourceId,
3745:                            myResourceId);
3746:
3747:                    if (directCompare) {
3748:                        return true;
3749:                    }
3750:                }
3751:
3752:                return false;
3753:            }
3754:
3755:            protected boolean isServerTzUTC() {
3756:                return this .isServerTzUTC;
3757:            }
3758:
3759:            private boolean usingCachedConfig = false;
3760:
3761:            /**
3762:             * Loads the result of 'SHOW VARIABLES' into the serverVariables field so
3763:             * that the driver can configure itself.
3764:             * 
3765:             * @throws SQLException
3766:             *             if the 'SHOW VARIABLES' query fails for any reason.
3767:             */
3768:            private void loadServerVariables() throws SQLException {
3769:
3770:                if (getCacheServerConfiguration()) {
3771:                    synchronized (serverConfigByUrl) {
3772:                        Map cachedVariableMap = (Map) serverConfigByUrl
3773:                                .get(getURL());
3774:
3775:                        if (cachedVariableMap != null) {
3776:                            this .serverVariables = cachedVariableMap;
3777:                            this .usingCachedConfig = true;
3778:
3779:                            return;
3780:                        }
3781:                    }
3782:                }
3783:
3784:                java.sql.Statement stmt = null;
3785:                java.sql.ResultSet results = null;
3786:
3787:                try {
3788:                    stmt = createStatement();
3789:                    stmt.setEscapeProcessing(false);
3790:
3791:                    results = stmt.executeQuery("SHOW VARIABLES");
3792:
3793:                    while (results.next()) {
3794:                        this .serverVariables.put(results.getString(1), results
3795:                                .getString(2));
3796:                    }
3797:
3798:                    if (getCacheServerConfiguration()) {
3799:                        synchronized (serverConfigByUrl) {
3800:                            serverConfigByUrl.put(getURL(),
3801:                                    this .serverVariables);
3802:                        }
3803:                    }
3804:                } catch (SQLException e) {
3805:                    throw e;
3806:                } finally {
3807:                    if (results != null) {
3808:                        try {
3809:                            results.close();
3810:                        } catch (SQLException sqlE) {
3811:                            ;
3812:                        }
3813:                    }
3814:
3815:                    if (stmt != null) {
3816:                        try {
3817:                            stmt.close();
3818:                        } catch (SQLException sqlE) {
3819:                            ;
3820:                        }
3821:                    }
3822:                }
3823:            }
3824:
3825:            /**
3826:             * Is the server configured to use lower-case table names only?
3827:             * 
3828:             * @return true if lower_case_table_names is 'on'
3829:             */
3830:            public boolean lowerCaseTableNames() {
3831:                return this .lowerCaseTableNames;
3832:            }
3833:
3834:            /**
3835:             * Has the maxRows value changed?
3836:             * 
3837:             * @param stmt
3838:             *            DOCUMENT ME!
3839:             */
3840:            void maxRowsChanged(StatementImpl stmt) {
3841:                synchronized (this .mutex) {
3842:                    if (this .statementsUsingMaxRows == null) {
3843:                        this .statementsUsingMaxRows = new HashMap();
3844:                    }
3845:
3846:                    this .statementsUsingMaxRows.put(stmt, stmt);
3847:
3848:                    this .maxRowsChanged = true;
3849:                }
3850:            }
3851:
3852:            /**
3853:             * A driver may convert the JDBC sql grammar into its system's native SQL
3854:             * grammar prior to sending it; nativeSQL returns the native form of the
3855:             * statement that the driver would have sent.
3856:             * 
3857:             * @param sql
3858:             *            a SQL statement that may contain one or more '?' parameter
3859:             *            placeholders
3860:             * @return the native form of this statement
3861:             * @exception SQLException
3862:             *                if a database access error occurs
3863:             */
3864:            public String nativeSQL(String sql) throws SQLException {
3865:                if (sql == null) {
3866:                    return null;
3867:                }
3868:
3869:                Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
3870:                        serverSupportsConvertFn(), this );
3871:
3872:                if (escapedSqlResult instanceof  String) {
3873:                    return (String) escapedSqlResult;
3874:                }
3875:
3876:                return ((EscapeProcessorResult) escapedSqlResult).escapedSql;
3877:            }
3878:
3879:            private CallableStatement parseCallableStatement(String sql)
3880:                    throws SQLException {
3881:                Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
3882:                        serverSupportsConvertFn(), this );
3883:
3884:                boolean isFunctionCall = false;
3885:                String parsedSql = null;
3886:
3887:                if (escapedSqlResult instanceof  EscapeProcessorResult) {
3888:                    parsedSql = ((EscapeProcessorResult) escapedSqlResult).escapedSql;
3889:                    isFunctionCall = ((EscapeProcessorResult) escapedSqlResult).callingStoredFunction;
3890:                } else {
3891:                    parsedSql = (String) escapedSqlResult;
3892:                    isFunctionCall = false;
3893:                }
3894:
3895:                return CallableStatement.getInstance(this , parsedSql,
3896:                        this .database, isFunctionCall);
3897:            }
3898:
3899:            /**
3900:             * DOCUMENT ME!
3901:             * 
3902:             * @return DOCUMENT ME!
3903:             */
3904:            public boolean parserKnowsUnicode() {
3905:                return this .parserKnowsUnicode;
3906:            }
3907:
3908:            /**
3909:             * Detect if the connection is still good
3910:             * 
3911:             * @throws SQLException
3912:             *             if the ping fails
3913:             */
3914:            public void ping() throws SQLException {
3915:                pingInternal(true);
3916:            }
3917:
3918:            protected void pingInternal(boolean checkForClosedConnection)
3919:                    throws SQLException {
3920:                if (checkForClosedConnection) {
3921:                    checkClosed();
3922:                }
3923:
3924:                // Need MySQL-3.22.1, but who uses anything older!?
3925:                this .io.sendCommand(MysqlDefs.PING, null, null, false, null);
3926:            }
3927:
3928:            /**
3929:             * DOCUMENT ME!
3930:             * 
3931:             * @param sql
3932:             *            DOCUMENT ME!
3933:             * @return DOCUMENT ME!
3934:             * @throws SQLException
3935:             *             DOCUMENT ME!
3936:             */
3937:            public java.sql.CallableStatement prepareCall(String sql)
3938:                    throws SQLException {
3939:
3940:                return prepareCall(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY,
3941:                        java.sql.ResultSet.CONCUR_READ_ONLY);
3942:            }
3943:
3944:            /**
3945:             * JDBC 2.0 Same as prepareCall() above, but allows the default result set
3946:             * type and result set concurrency type to be overridden.
3947:             * 
3948:             * @param sql
3949:             *            the SQL representing the callable statement
3950:             * @param resultSetType
3951:             *            a result set type, see ResultSet.TYPE_XXX
3952:             * @param resultSetConcurrency
3953:             *            a concurrency type, see ResultSet.CONCUR_XXX
3954:             * @return a new CallableStatement object containing the pre-compiled SQL
3955:             *         statement
3956:             * @exception SQLException
3957:             *                if a database-access error occurs.
3958:             */
3959:            public java.sql.CallableStatement prepareCall(String sql,
3960:                    int resultSetType, int resultSetConcurrency)
3961:                    throws SQLException {
3962:                if (versionMeetsMinimum(5, 0, 0)) {
3963:                    CallableStatement cStmt = null;
3964:
3965:                    if (!getCacheCallableStatements()) {
3966:
3967:                        cStmt = parseCallableStatement(sql);
3968:                    } else {
3969:                        synchronized (this .parsedCallableStatementCache) {
3970:                            CompoundCacheKey key = new CompoundCacheKey(
3971:                                    getCatalog(), sql);
3972:
3973:                            CallableStatement.CallableStatementParamInfo cachedParamInfo = (CallableStatement.CallableStatementParamInfo) this .parsedCallableStatementCache
3974:                                    .get(key);
3975:
3976:                            if (cachedParamInfo != null) {
3977:                                cStmt = CallableStatement.getInstance(this ,
3978:                                        cachedParamInfo);
3979:                            } else {
3980:                                cStmt = parseCallableStatement(sql);
3981:
3982:                                cachedParamInfo = cStmt.paramInfo;
3983:
3984:                                this .parsedCallableStatementCache.put(key,
3985:                                        cachedParamInfo);
3986:                            }
3987:                        }
3988:                    }
3989:
3990:                    cStmt.setResultSetType(resultSetType);
3991:                    cStmt.setResultSetConcurrency(resultSetConcurrency);
3992:
3993:                    return cStmt;
3994:                }
3995:
3996:                throw SQLError.createSQLException("Callable statements not "
3997:                        + "supported.", SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
3998:            }
3999:
4000:            /**
4001:             * @see Connection#prepareCall(String, int, int, int)
4002:             */
4003:            public java.sql.CallableStatement prepareCall(String sql,
4004:                    int resultSetType, int resultSetConcurrency,
4005:                    int resultSetHoldability) throws SQLException {
4006:                if (getPedantic()) {
4007:                    if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
4008:                        throw SQLError
4009:                                .createSQLException(
4010:                                        "HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
4011:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4012:                    }
4013:                }
4014:
4015:                CallableStatement cStmt = (com.mysql.jdbc.CallableStatement) prepareCall(
4016:                        sql, resultSetType, resultSetConcurrency);
4017:
4018:                return cStmt;
4019:            }
4020:
4021:            /**
4022:             * A SQL statement with or without IN parameters can be pre-compiled and
4023:             * stored in a PreparedStatement object. This object can then be used to
4024:             * efficiently execute this statement multiple times.
4025:             * <p>
4026:             * <B>Note:</B> This method is optimized for handling parametric SQL
4027:             * statements that benefit from precompilation if the driver supports
4028:             * precompilation. In this case, the statement is not sent to the database
4029:             * until the PreparedStatement is executed. This has no direct effect on
4030:             * users; however it does affect which method throws certain
4031:             * java.sql.SQLExceptions
4032:             * </p>
4033:             * <p>
4034:             * MySQL does not support precompilation of statements, so they are handled
4035:             * by the driver.
4036:             * </p>
4037:             * 
4038:             * @param sql
4039:             *            a SQL statement that may contain one or more '?' IN parameter
4040:             *            placeholders
4041:             * @return a new PreparedStatement object containing the pre-compiled
4042:             *         statement.
4043:             * @exception SQLException
4044:             *                if a database access error occurs.
4045:             */
4046:            public java.sql.PreparedStatement prepareStatement(String sql)
4047:                    throws SQLException {
4048:                return prepareStatement(sql,
4049:                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
4050:                        java.sql.ResultSet.CONCUR_READ_ONLY);
4051:            }
4052:
4053:            /**
4054:             * @see Connection#prepareStatement(String, int)
4055:             */
4056:            public java.sql.PreparedStatement prepareStatement(String sql,
4057:                    int autoGenKeyIndex) throws SQLException {
4058:                java.sql.PreparedStatement pStmt = prepareStatement(sql);
4059:
4060:                ((com.mysql.jdbc.PreparedStatement) pStmt)
4061:                        .setRetrieveGeneratedKeys(autoGenKeyIndex == java.sql.Statement.RETURN_GENERATED_KEYS);
4062:
4063:                return pStmt;
4064:            }
4065:
4066:            /**
4067:             * JDBC 2.0 Same as prepareStatement() above, but allows the default result
4068:             * set type and result set concurrency type to be overridden.
4069:             * 
4070:             * @param sql
4071:             *            the SQL query containing place holders
4072:             * @param resultSetType
4073:             *            a result set type, see ResultSet.TYPE_XXX
4074:             * @param resultSetConcurrency
4075:             *            a concurrency type, see ResultSet.CONCUR_XXX
4076:             * @return a new PreparedStatement object containing the pre-compiled SQL
4077:             *         statement
4078:             * @exception SQLException
4079:             *                if a database-access error occurs.
4080:             */
4081:            public java.sql.PreparedStatement prepareStatement(String sql,
4082:                    int resultSetType, int resultSetConcurrency)
4083:                    throws SQLException {
4084:                checkClosed();
4085:
4086:                //
4087:                // FIXME: Create warnings if can't create results of the given
4088:                // type or concurrency
4089:                //
4090:                PreparedStatement pStmt = null;
4091:
4092:                boolean canServerPrepare = true;
4093:
4094:                String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql)
4095:                        : sql;
4096:
4097:                if (getEmulateUnsupportedPstmts()) {
4098:                    canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);
4099:                }
4100:
4101:                if (this .useServerPreparedStmts && canServerPrepare) {
4102:                    if (this .getCachePreparedStatements()) {
4103:                        synchronized (this .serverSideStatementCache) {
4104:                            pStmt = (com.mysql.jdbc.ServerPreparedStatement) this .serverSideStatementCache
4105:                                    .remove(sql);
4106:
4107:                            if (pStmt != null) {
4108:                                ((com.mysql.jdbc.ServerPreparedStatement) pStmt)
4109:                                        .setClosed(false);
4110:                                pStmt.clearParameters();
4111:                            }
4112:
4113:                            if (pStmt == null) {
4114:                                try {
4115:                                    pStmt = ServerPreparedStatement
4116:                                            .getInstance(this , nativeSql,
4117:                                                    this .database,
4118:                                                    resultSetType,
4119:                                                    resultSetConcurrency);
4120:                                    if (sql.length() < getPreparedStatementCacheSqlLimit()) {
4121:                                        ((com.mysql.jdbc.ServerPreparedStatement) pStmt).isCached = true;
4122:                                    }
4123:
4124:                                    pStmt.setResultSetType(resultSetType);
4125:                                    pStmt
4126:                                            .setResultSetConcurrency(resultSetConcurrency);
4127:                                } catch (SQLException sqlEx) {
4128:                                    // Punt, if necessary
4129:                                    if (getEmulateUnsupportedPstmts()) {
4130:                                        pStmt = clientPrepareStatement(
4131:                                                nativeSql, resultSetType,
4132:                                                resultSetConcurrency, false);
4133:
4134:                                        if (sql.length() < getPreparedStatementCacheSqlLimit()) {
4135:                                            this .serverSideStatementCheckCache
4136:                                                    .put(sql, Boolean.FALSE);
4137:                                        }
4138:                                    } else {
4139:                                        throw sqlEx;
4140:                                    }
4141:                                }
4142:                            }
4143:                        }
4144:                    } else {
4145:                        try {
4146:                            pStmt = ServerPreparedStatement.getInstance(this ,
4147:                                    nativeSql, this .database, resultSetType,
4148:                                    resultSetConcurrency);
4149:
4150:                            pStmt.setResultSetType(resultSetType);
4151:                            pStmt.setResultSetConcurrency(resultSetConcurrency);
4152:                        } catch (SQLException sqlEx) {
4153:                            // Punt, if necessary
4154:                            if (getEmulateUnsupportedPstmts()) {
4155:                                pStmt = clientPrepareStatement(nativeSql,
4156:                                        resultSetType, resultSetConcurrency,
4157:                                        false);
4158:                            } else {
4159:                                throw sqlEx;
4160:                            }
4161:                        }
4162:                    }
4163:                } else {
4164:                    pStmt = clientPrepareStatement(nativeSql, resultSetType,
4165:                            resultSetConcurrency, false);
4166:                }
4167:
4168:                return pStmt;
4169:            }
4170:
4171:            /**
4172:             * @see Connection#prepareStatement(String, int, int, int)
4173:             */
4174:            public java.sql.PreparedStatement prepareStatement(String sql,
4175:                    int resultSetType, int resultSetConcurrency,
4176:                    int resultSetHoldability) throws SQLException {
4177:                if (getPedantic()) {
4178:                    if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
4179:                        throw SQLError
4180:                                .createSQLException(
4181:                                        "HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
4182:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4183:                    }
4184:                }
4185:
4186:                return prepareStatement(sql, resultSetType,
4187:                        resultSetConcurrency);
4188:            }
4189:
4190:            /**
4191:             * @see Connection#prepareStatement(String, int[])
4192:             */
4193:            public java.sql.PreparedStatement prepareStatement(String sql,
4194:                    int[] autoGenKeyIndexes) throws SQLException {
4195:                java.sql.PreparedStatement pStmt = prepareStatement(sql);
4196:
4197:                ((com.mysql.jdbc.PreparedStatement) pStmt)
4198:                        .setRetrieveGeneratedKeys((autoGenKeyIndexes != null)
4199:                                && (autoGenKeyIndexes.length > 0));
4200:
4201:                return pStmt;
4202:            }
4203:
4204:            /**
4205:             * @see Connection#prepareStatement(String, String[])
4206:             */
4207:            public java.sql.PreparedStatement prepareStatement(String sql,
4208:                    String[] autoGenKeyColNames) throws SQLException {
4209:                java.sql.PreparedStatement pStmt = prepareStatement(sql);
4210:
4211:                ((com.mysql.jdbc.PreparedStatement) pStmt)
4212:                        .setRetrieveGeneratedKeys((autoGenKeyColNames != null)
4213:                                && (autoGenKeyColNames.length > 0));
4214:
4215:                return pStmt;
4216:            }
4217:
4218:            /**
4219:             * Closes connection and frees resources.
4220:             * 
4221:             * @param calledExplicitly
4222:             *            is this being called from close()
4223:             * @param issueRollback
4224:             *            should a rollback() be issued?
4225:             * @throws SQLException
4226:             *             if an error occurs
4227:             */
4228:            protected void realClose(boolean calledExplicitly,
4229:                    boolean issueRollback, boolean skipLocalTeardown,
4230:                    Throwable reason) throws SQLException {
4231:                SQLException sqlEx = null;
4232:
4233:                if (this .isClosed()) {
4234:                    return;
4235:                }
4236:
4237:                this .forceClosedReason = reason;
4238:
4239:                try {
4240:                    if (!skipLocalTeardown) {
4241:                        if (!getAutoCommit() && issueRollback) {
4242:                            try {
4243:                                rollback();
4244:                            } catch (SQLException ex) {
4245:                                sqlEx = ex;
4246:                            }
4247:                        }
4248:
4249:                        reportMetrics();
4250:
4251:                        if (getUseUsageAdvisor()) {
4252:                            if (!calledExplicitly) {
4253:                                String message = "Connection implicitly closed by Driver. You should call Connection.close() from your code to free resources more efficiently and avoid resource leaks.";
4254:
4255:                                this .eventSink.consumeEvent(new ProfilerEvent(
4256:                                        ProfilerEvent.TYPE_WARN,
4257:                                        "", //$NON-NLS-1$
4258:                                        this .getCatalog(), this .getId(), -1,
4259:                                        -1, System.currentTimeMillis(), 0,
4260:                                        Constants.MILLIS_I18N, null,
4261:                                        this .pointOfOrigin, message));
4262:                            }
4263:
4264:                            long connectionLifeTime = System
4265:                                    .currentTimeMillis()
4266:                                    - this .connectionCreationTimeMillis;
4267:
4268:                            if (connectionLifeTime < 500) {
4269:                                String message = "Connection lifetime of < .5 seconds. You might be un-necessarily creating short-lived connections and should investigate connection pooling to be more efficient.";
4270:
4271:                                this .eventSink.consumeEvent(new ProfilerEvent(
4272:                                        ProfilerEvent.TYPE_WARN,
4273:                                        "", //$NON-NLS-1$
4274:                                        this .getCatalog(), this .getId(), -1,
4275:                                        -1, System.currentTimeMillis(), 0,
4276:                                        Constants.MILLIS_I18N, null,
4277:                                        this .pointOfOrigin, message));
4278:                            }
4279:                        }
4280:
4281:                        try {
4282:                            closeAllOpenStatements();
4283:                        } catch (SQLException ex) {
4284:                            sqlEx = ex;
4285:                        }
4286:
4287:                        if (this .io != null) {
4288:                            try {
4289:                                this .io.quit();
4290:                            } catch (Exception e) {
4291:                                ;
4292:                            }
4293:
4294:                        }
4295:                    } else {
4296:                        this .io.forceClose();
4297:                    }
4298:                } finally {
4299:                    this .openStatements = null;
4300:                    this .io = null;
4301:                    ProfileEventSink.removeInstance(this );
4302:                    this .isClosed = true;
4303:                }
4304:
4305:                if (sqlEx != null) {
4306:                    throw sqlEx;
4307:                }
4308:
4309:            }
4310:
4311:            protected void recachePreparedStatement(
4312:                    ServerPreparedStatement pstmt) throws SQLException {
4313:                if (pstmt.isPoolable()) {
4314:                    synchronized (this .serverSideStatementCache) {
4315:                        this .serverSideStatementCache.put(pstmt.originalSql,
4316:                                pstmt);
4317:                    }
4318:                }
4319:            }
4320:
4321:            /**
4322:             * DOCUMENT ME!
4323:             * 
4324:             * @param queryTimeMs
4325:             */
4326:            protected void registerQueryExecutionTime(long queryTimeMs) {
4327:                if (queryTimeMs > this .longestQueryTimeMs) {
4328:                    this .longestQueryTimeMs = queryTimeMs;
4329:
4330:                    repartitionPerformanceHistogram();
4331:                }
4332:
4333:                addToPerformanceHistogram(queryTimeMs, 1);
4334:
4335:                if (queryTimeMs < this .shortestQueryTimeMs) {
4336:                    this .shortestQueryTimeMs = (queryTimeMs == 0) ? 1
4337:                            : queryTimeMs;
4338:                }
4339:
4340:                this .numberOfQueriesIssued++;
4341:
4342:                this .totalQueryTimeMs += queryTimeMs;
4343:            }
4344:
4345:            /**
4346:             * Register a Statement instance as open.
4347:             * 
4348:             * @param stmt
4349:             *            the Statement instance to remove
4350:             */
4351:            void registerStatement(StatementImpl stmt) {
4352:                synchronized (this .openStatements) {
4353:                    this .openStatements.put(stmt, stmt);
4354:                }
4355:            }
4356:
4357:            /**
4358:             * @see Connection#releaseSavepoint(Savepoint)
4359:             */
4360:            public void releaseSavepoint(Savepoint arg0) throws SQLException {
4361:                // this is a no-op
4362:            }
4363:
4364:            private void repartitionHistogram(int[] histCounts,
4365:                    long[] histBreakpoints, long currentLowerBound,
4366:                    long currentUpperBound) {
4367:
4368:                if (oldHistCounts == null) {
4369:                    oldHistCounts = new int[histCounts.length];
4370:                    oldHistBreakpoints = new long[histBreakpoints.length];
4371:                }
4372:
4373:                System.arraycopy(histCounts, 0, oldHistCounts, 0,
4374:                        histCounts.length);
4375:
4376:                System.arraycopy(histBreakpoints, 0, oldHistBreakpoints, 0,
4377:                        histBreakpoints.length);
4378:
4379:                createInitialHistogram(histBreakpoints, currentLowerBound,
4380:                        currentUpperBound);
4381:
4382:                for (int i = 0; i < HISTOGRAM_BUCKETS; i++) {
4383:                    addToHistogram(histCounts, histBreakpoints,
4384:                            oldHistBreakpoints[i], oldHistCounts[i],
4385:                            currentLowerBound, currentUpperBound);
4386:                }
4387:            }
4388:
4389:            private void repartitionPerformanceHistogram() {
4390:                checkAndCreatePerformanceHistogram();
4391:
4392:                repartitionHistogram(this .perfMetricsHistCounts,
4393:                        this .perfMetricsHistBreakpoints,
4394:                        this .shortestQueryTimeMs == Long.MAX_VALUE ? 0
4395:                                : this .shortestQueryTimeMs,
4396:                        this .longestQueryTimeMs);
4397:            }
4398:
4399:            private void repartitionTablesAccessedHistogram() {
4400:                checkAndCreateTablesAccessedHistogram();
4401:
4402:                repartitionHistogram(this .numTablesMetricsHistCounts,
4403:                        this .numTablesMetricsHistBreakpoints,
4404:                        this .minimumNumberTablesAccessed == Long.MAX_VALUE ? 0
4405:                                : this .minimumNumberTablesAccessed,
4406:                        this .maximumNumberTablesAccessed);
4407:            }
4408:
4409:            private void reportMetrics() {
4410:                if (getGatherPerformanceMetrics()) {
4411:                    StringBuffer logMessage = new StringBuffer(256);
4412:
4413:                    logMessage.append("** Performance Metrics Report **\n");
4414:                    logMessage.append("\nLongest reported query: "
4415:                            + this .longestQueryTimeMs + " ms");
4416:                    logMessage.append("\nShortest reported query: "
4417:                            + this .shortestQueryTimeMs + " ms");
4418:                    logMessage
4419:                            .append("\nAverage query execution time: "
4420:                                    + (this .totalQueryTimeMs / this .numberOfQueriesIssued)
4421:                                    + " ms");
4422:                    logMessage.append("\nNumber of statements executed: "
4423:                            + this .numberOfQueriesIssued);
4424:                    logMessage.append("\nNumber of result sets created: "
4425:                            + this .numberOfResultSetsCreated);
4426:                    logMessage.append("\nNumber of statements prepared: "
4427:                            + this .numberOfPrepares);
4428:                    logMessage
4429:                            .append("\nNumber of prepared statement executions: "
4430:                                    + this .numberOfPreparedExecutes);
4431:
4432:                    if (this .perfMetricsHistBreakpoints != null) {
4433:                        logMessage.append("\n\n\tTiming Histogram:\n");
4434:                        int maxNumPoints = 20;
4435:                        int highestCount = Integer.MIN_VALUE;
4436:
4437:                        for (int i = 0; i < (HISTOGRAM_BUCKETS); i++) {
4438:                            if (this .perfMetricsHistCounts[i] > highestCount) {
4439:                                highestCount = this .perfMetricsHistCounts[i];
4440:                            }
4441:                        }
4442:
4443:                        if (highestCount == 0) {
4444:                            highestCount = 1; // avoid DIV/0
4445:                        }
4446:
4447:                        for (int i = 0; i < (HISTOGRAM_BUCKETS - 1); i++) {
4448:
4449:                            if (i == 0) {
4450:                                logMessage
4451:                                        .append("\n\tless than "
4452:                                                + this .perfMetricsHistBreakpoints[i + 1]
4453:                                                + " ms: \t"
4454:                                                + this .perfMetricsHistCounts[i]);
4455:                            } else {
4456:                                logMessage
4457:                                        .append("\n\tbetween "
4458:                                                + this .perfMetricsHistBreakpoints[i]
4459:                                                + " and "
4460:                                                + this .perfMetricsHistBreakpoints[i + 1]
4461:                                                + " ms: \t"
4462:                                                + this .perfMetricsHistCounts[i]);
4463:                            }
4464:
4465:                            logMessage.append("\t");
4466:
4467:                            int numPointsToGraph = (int) (maxNumPoints * ((double) this .perfMetricsHistCounts[i] / (double) highestCount));
4468:
4469:                            for (int j = 0; j < numPointsToGraph; j++) {
4470:                                logMessage.append("*");
4471:                            }
4472:
4473:                            if (this .longestQueryTimeMs < this .perfMetricsHistCounts[i + 1]) {
4474:                                break;
4475:                            }
4476:                        }
4477:
4478:                        if (this .perfMetricsHistBreakpoints[HISTOGRAM_BUCKETS - 2] < this .longestQueryTimeMs) {
4479:                            logMessage.append("\n\tbetween ");
4480:                            logMessage
4481:                                    .append(this .perfMetricsHistBreakpoints[HISTOGRAM_BUCKETS - 2]);
4482:                            logMessage.append(" and ");
4483:                            logMessage
4484:                                    .append(this .perfMetricsHistBreakpoints[HISTOGRAM_BUCKETS - 1]);
4485:                            logMessage.append(" ms: \t");
4486:                            logMessage
4487:                                    .append(this .perfMetricsHistCounts[HISTOGRAM_BUCKETS - 1]);
4488:                        }
4489:                    }
4490:
4491:                    if (this .numTablesMetricsHistBreakpoints != null) {
4492:                        logMessage.append("\n\n\tTable Join Histogram:\n");
4493:                        int maxNumPoints = 20;
4494:                        int highestCount = Integer.MIN_VALUE;
4495:
4496:                        for (int i = 0; i < (HISTOGRAM_BUCKETS); i++) {
4497:                            if (this .numTablesMetricsHistCounts[i] > highestCount) {
4498:                                highestCount = this .numTablesMetricsHistCounts[i];
4499:                            }
4500:                        }
4501:
4502:                        if (highestCount == 0) {
4503:                            highestCount = 1; // avoid DIV/0
4504:                        }
4505:
4506:                        for (int i = 0; i < (HISTOGRAM_BUCKETS - 1); i++) {
4507:
4508:                            if (i == 0) {
4509:                                logMessage
4510:                                        .append("\n\t"
4511:                                                + this .numTablesMetricsHistBreakpoints[i + 1]
4512:                                                + " tables or less: \t\t"
4513:                                                + this .numTablesMetricsHistCounts[i]);
4514:                            } else {
4515:                                logMessage
4516:                                        .append("\n\tbetween "
4517:                                                + this .numTablesMetricsHistBreakpoints[i]
4518:                                                + " and "
4519:                                                + this .numTablesMetricsHistBreakpoints[i + 1]
4520:                                                + " tables: \t"
4521:                                                + this .numTablesMetricsHistCounts[i]);
4522:                            }
4523:
4524:                            logMessage.append("\t");
4525:
4526:                            int numPointsToGraph = (int) (maxNumPoints * ((double) this .numTablesMetricsHistCounts[i] / (double) highestCount));
4527:
4528:                            for (int j = 0; j < numPointsToGraph; j++) {
4529:                                logMessage.append("*");
4530:                            }
4531:
4532:                            if (this .maximumNumberTablesAccessed < this .numTablesMetricsHistBreakpoints[i + 1]) {
4533:                                break;
4534:                            }
4535:                        }
4536:
4537:                        if (this .numTablesMetricsHistBreakpoints[HISTOGRAM_BUCKETS - 2] < this .maximumNumberTablesAccessed) {
4538:                            logMessage.append("\n\tbetween ");
4539:                            logMessage
4540:                                    .append(this .numTablesMetricsHistBreakpoints[HISTOGRAM_BUCKETS - 2]);
4541:                            logMessage.append(" and ");
4542:                            logMessage
4543:                                    .append(this .numTablesMetricsHistBreakpoints[HISTOGRAM_BUCKETS - 1]);
4544:                            logMessage.append(" tables: ");
4545:                            logMessage
4546:                                    .append(this .numTablesMetricsHistCounts[HISTOGRAM_BUCKETS - 1]);
4547:                        }
4548:                    }
4549:
4550:                    this .log.logInfo(logMessage);
4551:
4552:                    this .metricsLastReportedMs = System.currentTimeMillis();
4553:                }
4554:            }
4555:
4556:            /**
4557:             * Reports currently collected metrics if this feature is enabled and the
4558:             * timeout has passed.
4559:             */
4560:            private void reportMetricsIfNeeded() {
4561:                if (getGatherPerformanceMetrics()) {
4562:                    if ((System.currentTimeMillis() - this .metricsLastReportedMs) > getReportMetricsIntervalMillis()) {
4563:                        reportMetrics();
4564:                    }
4565:                }
4566:            }
4567:
4568:            protected void reportNumberOfTablesAccessed(int numTablesAccessed) {
4569:                if (numTablesAccessed < this .minimumNumberTablesAccessed) {
4570:                    this .minimumNumberTablesAccessed = numTablesAccessed;
4571:                }
4572:
4573:                if (numTablesAccessed > this .maximumNumberTablesAccessed) {
4574:                    this .maximumNumberTablesAccessed = numTablesAccessed;
4575:
4576:                    repartitionTablesAccessedHistogram();
4577:                }
4578:
4579:                addToTablesAccessedHistogram(numTablesAccessed, 1);
4580:            }
4581:
4582:            /**
4583:             * Resets the server-side state of this connection. Doesn't work for MySQL
4584:             * versions older than 4.0.6 or if isParanoid() is set (it will become a
4585:             * no-op in these cases). Usually only used from connection pooling code.
4586:             * 
4587:             * @throws SQLException
4588:             *             if the operation fails while resetting server state.
4589:             */
4590:            public void resetServerState() throws SQLException {
4591:                if (!getParanoid()
4592:                        && ((this .io != null) && versionMeetsMinimum(4, 0, 6))) {
4593:                    changeUser(this .user, this .password);
4594:                }
4595:            }
4596:
4597:            /**
4598:             * The method rollback() drops all changes made since the previous
4599:             * commit/rollback and releases any database locks currently held by the
4600:             * Connection.
4601:             * 
4602:             * @exception SQLException
4603:             *                if a database access error occurs
4604:             * @see commit
4605:             */
4606:            public void rollback() throws SQLException {
4607:                synchronized (getMutex()) {
4608:                    checkClosed();
4609:
4610:                    try {
4611:                        // no-op if _relaxAutoCommit == true
4612:                        if (this .autoCommit && !getRelaxAutoCommit()) {
4613:                            throw SQLError.createSQLException(
4614:                                    "Can't call rollback when autocommit=true",
4615:                                    SQLError.SQL_STATE_CONNECTION_NOT_OPEN);
4616:                        } else if (this .transactionsSupported) {
4617:                            try {
4618:                                rollbackNoChecks();
4619:                            } catch (SQLException sqlEx) {
4620:                                // We ignore non-transactional tables if told to do so
4621:                                if (getIgnoreNonTxTables()
4622:                                        && (sqlEx.getErrorCode() != SQLError.ER_WARNING_NOT_COMPLETE_ROLLBACK)) {
4623:                                    throw sqlEx;
4624:                                }
4625:                            }
4626:                        }
4627:                    } catch (SQLException sqlException) {
4628:                        if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
4629:                                .equals(sqlException.getSQLState())) {
4630:                            throw SQLError
4631:                                    .createSQLException(
4632:                                            "Communications link failure during rollback(). Transaction resolution unknown.",
4633:                                            SQLError.SQL_STATE_TRANSACTION_RESOLUTION_UNKNOWN);
4634:                        }
4635:
4636:                        throw sqlException;
4637:                    } finally {
4638:                        this .needsPing = this .getReconnectAtTxEnd();
4639:                    }
4640:                }
4641:            }
4642:
4643:            /**
4644:             * @see Connection#rollback(Savepoint)
4645:             */
4646:            public void rollback(Savepoint savepoint) throws SQLException {
4647:
4648:                if (versionMeetsMinimum(4, 0, 14)
4649:                        || versionMeetsMinimum(4, 1, 1)) {
4650:                    synchronized (getMutex()) {
4651:                        checkClosed();
4652:
4653:                        try {
4654:                            StringBuffer rollbackQuery = new StringBuffer(
4655:                                    "ROLLBACK TO SAVEPOINT ");
4656:                            rollbackQuery.append('`');
4657:                            rollbackQuery.append(savepoint.getSavepointName());
4658:                            rollbackQuery.append('`');
4659:
4660:                            java.sql.Statement stmt = null;
4661:
4662:                            try {
4663:                                stmt = createStatement();
4664:
4665:                                stmt.executeUpdate(rollbackQuery.toString());
4666:                            } catch (SQLException sqlEx) {
4667:                                int errno = sqlEx.getErrorCode();
4668:
4669:                                if (errno == 1181) {
4670:                                    String msg = sqlEx.getMessage();
4671:
4672:                                    if (msg != null) {
4673:                                        int indexOfError153 = msg
4674:                                                .indexOf("153");
4675:
4676:                                        if (indexOfError153 != -1) {
4677:                                            throw SQLError
4678:                                                    .createSQLException(
4679:                                                            "Savepoint '"
4680:                                                                    + savepoint
4681:                                                                            .getSavepointName()
4682:                                                                    + "' does not exist",
4683:                                                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
4684:                                                            errno);
4685:                                        }
4686:                                    }
4687:                                }
4688:
4689:                                // We ignore non-transactional tables if told to do so
4690:                                if (getIgnoreNonTxTables()
4691:                                        && (sqlEx.getErrorCode() != SQLError.ER_WARNING_NOT_COMPLETE_ROLLBACK)) {
4692:                                    throw sqlEx;
4693:                                }
4694:
4695:                                if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
4696:                                        .equals(sqlEx.getSQLState())) {
4697:                                    throw SQLError
4698:                                            .createSQLException(
4699:                                                    "Communications link failure during rollback(). Transaction resolution unknown.",
4700:                                                    SQLError.SQL_STATE_TRANSACTION_RESOLUTION_UNKNOWN);
4701:                                }
4702:
4703:                                throw sqlEx;
4704:                            } finally {
4705:                                closeStatement(stmt);
4706:                            }
4707:                        } finally {
4708:                            this .needsPing = this .getReconnectAtTxEnd();
4709:                        }
4710:                    }
4711:                } else {
4712:                    throw new NotImplemented();
4713:                }
4714:            }
4715:
4716:            private void rollbackNoChecks() throws SQLException {
4717:                if (getUseLocalSessionState() && versionMeetsMinimum(5, 0, 0)) {
4718:                    if (!this .io.inTransactionOnServer()) {
4719:                        return; // effectively a no-op
4720:                    }
4721:                }
4722:
4723:                execSQL(null, "rollback", -1, null,
4724:                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
4725:                        java.sql.ResultSet.CONCUR_READ_ONLY, false,
4726:                        this .database, null, false);
4727:            }
4728:
4729:            /**
4730:             * @see java.sql.Connection#prepareStatement(String)
4731:             */
4732:            public ServerPreparedStatement serverPrepareStatement(String sql)
4733:                    throws SQLException {
4734:
4735:                String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql)
4736:                        : sql;
4737:
4738:                return ServerPreparedStatement.getInstance(this , nativeSql,
4739:                        this .getCatalog(),
4740:                        java.sql.ResultSet.TYPE_SCROLL_SENSITIVE,
4741:                        java.sql.ResultSet.CONCUR_READ_ONLY);
4742:            }
4743:
4744:            /**
4745:             * @see java.sql.Connection#prepareStatement(String, int)
4746:             */
4747:            public java.sql.PreparedStatement serverPrepareStatement(
4748:                    String sql, int autoGenKeyIndex) throws SQLException {
4749:                String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql)
4750:                        : sql;
4751:
4752:                PreparedStatement pStmt = ServerPreparedStatement.getInstance(
4753:                        this , nativeSql, this .getCatalog(),
4754:                        java.sql.ResultSet.TYPE_SCROLL_SENSITIVE,
4755:                        java.sql.ResultSet.CONCUR_READ_ONLY);
4756:
4757:                pStmt
4758:                        .setRetrieveGeneratedKeys(autoGenKeyIndex == java.sql.Statement.RETURN_GENERATED_KEYS);
4759:
4760:                return pStmt;
4761:            }
4762:
4763:            /**
4764:             * @see java.sql.Connection#prepareStatement(String, int, int)
4765:             */
4766:            public java.sql.PreparedStatement serverPrepareStatement(
4767:                    String sql, int resultSetType, int resultSetConcurrency)
4768:                    throws SQLException {
4769:                String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql)
4770:                        : sql;
4771:
4772:                return ServerPreparedStatement.getInstance(this , nativeSql,
4773:                        this .getCatalog(), resultSetType, resultSetConcurrency);
4774:            }
4775:
4776:            /**
4777:             * @see java.sql.Connection#prepareStatement(String, int, int, int)
4778:             */
4779:            public java.sql.PreparedStatement serverPrepareStatement(
4780:                    String sql, int resultSetType, int resultSetConcurrency,
4781:                    int resultSetHoldability) throws SQLException {
4782:                if (getPedantic()) {
4783:                    if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
4784:                        throw SQLError
4785:                                .createSQLException(
4786:                                        "HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
4787:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4788:                    }
4789:                }
4790:
4791:                return serverPrepareStatement(sql, resultSetType,
4792:                        resultSetConcurrency);
4793:            }
4794:
4795:            /**
4796:             * @see java.sql.Connection#prepareStatement(String, int[])
4797:             */
4798:            public java.sql.PreparedStatement serverPrepareStatement(
4799:                    String sql, int[] autoGenKeyIndexes) throws SQLException {
4800:
4801:                PreparedStatement pStmt = serverPrepareStatement(sql);
4802:
4803:                pStmt.setRetrieveGeneratedKeys((autoGenKeyIndexes != null)
4804:                        && (autoGenKeyIndexes.length > 0));
4805:
4806:                return pStmt;
4807:            }
4808:
4809:            /**
4810:             * @see java.sql.Connection#prepareStatement(String, String[])
4811:             */
4812:            public java.sql.PreparedStatement serverPrepareStatement(
4813:                    String sql, String[] autoGenKeyColNames)
4814:                    throws SQLException {
4815:                PreparedStatement pStmt = serverPrepareStatement(sql);
4816:
4817:                pStmt.setRetrieveGeneratedKeys((autoGenKeyColNames != null)
4818:                        && (autoGenKeyColNames.length > 0));
4819:
4820:                return pStmt;
4821:            }
4822:
4823:            protected boolean serverSupportsConvertFn() throws SQLException {
4824:                return versionMeetsMinimum(4, 0, 2);
4825:            }
4826:
4827:            /**
4828:             * If a connection is in auto-commit mode, than all its SQL statements will
4829:             * be executed and committed as individual transactions. Otherwise, its SQL
4830:             * statements are grouped into transactions that are terminated by either
4831:             * commit() or rollback(). By default, new connections are in auto- commit
4832:             * mode. The commit occurs when the statement completes or the next execute
4833:             * occurs, whichever comes first. In the case of statements returning a
4834:             * ResultSet, the statement completes when the last row of the ResultSet has
4835:             * been retrieved or the ResultSet has been closed. In advanced cases, a
4836:             * single statement may return multiple results as well as output parameter
4837:             * values. Here the commit occurs when all results and output param values
4838:             * have been retrieved.
4839:             * <p>
4840:             * <b>Note:</b> MySQL does not support transactions, so this method is a
4841:             * no-op.
4842:             * </p>
4843:             * 
4844:             * @param autoCommitFlag -
4845:             *            true enables auto-commit; false disables it
4846:             * @exception SQLException
4847:             *                if a database access error occurs
4848:             */
4849:            public void setAutoCommit(boolean autoCommitFlag)
4850:                    throws SQLException {
4851:                synchronized (getMutex()) {
4852:                    checkClosed();
4853:
4854:                    if (getAutoReconnectForPools()) {
4855:                        setHighAvailability(true);
4856:                    }
4857:
4858:                    try {
4859:                        if (this .transactionsSupported) {
4860:
4861:                            boolean needsSetOnServer = true;
4862:
4863:                            if (this .getUseLocalSessionState()
4864:                                    && this .autoCommit == autoCommitFlag) {
4865:                                needsSetOnServer = false;
4866:                            } else if (!this .getHighAvailability()) {
4867:                                needsSetOnServer = this .getIO()
4868:                                        .isSetNeededForAutoCommitMode(
4869:                                                autoCommitFlag);
4870:                            }
4871:
4872:                            // this internal value must be set first as failover depends on
4873:                            // it
4874:                            // being set to true to fail over (which is done by most
4875:                            // app servers and connection pools at the end of
4876:                            // a transaction), and the driver issues an implicit set
4877:                            // based on this value when it (re)-connects to a server
4878:                            // so the value holds across connections
4879:                            this .autoCommit = autoCommitFlag;
4880:
4881:                            if (needsSetOnServer) {
4882:                                execSQL(null,
4883:                                        autoCommitFlag ? "SET autocommit=1"
4884:                                                : "SET autocommit=0", -1, null,
4885:                                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
4886:                                        java.sql.ResultSet.CONCUR_READ_ONLY,
4887:                                        false, this .database, null, false);
4888:                            }
4889:
4890:                        } else {
4891:                            if ((autoCommitFlag == false)
4892:                                    && !getRelaxAutoCommit()) {
4893:                                throw SQLError
4894:                                        .createSQLException(
4895:                                                "MySQL Versions Older than 3.23.15 "
4896:                                                        + "do not support transactions",
4897:                                                SQLError.SQL_STATE_CONNECTION_NOT_OPEN);
4898:                            }
4899:
4900:                            this .autoCommit = autoCommitFlag;
4901:                        }
4902:                    } finally {
4903:                        if (this .getAutoReconnectForPools()) {
4904:                            setHighAvailability(false);
4905:                        }
4906:                    }
4907:
4908:                    return;
4909:                }
4910:            }
4911:
4912:            /**
4913:             * A sub-space of this Connection's database may be selected by setting a
4914:             * catalog name. If the driver does not support catalogs, it will silently
4915:             * ignore this request
4916:             * <p>
4917:             * <b>Note:</b> MySQL's notion of catalogs are individual databases.
4918:             * </p>
4919:             * 
4920:             * @param catalog
4921:             *            the database for this connection to use
4922:             * @throws SQLException
4923:             *             if a database access error occurs
4924:             */
4925:            public void setCatalog(String catalog) throws SQLException {
4926:                synchronized (getMutex()) {
4927:                    checkClosed();
4928:
4929:                    if (catalog == null) {
4930:                        throw SQLError.createSQLException(
4931:                                "Catalog can not be null",
4932:                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4933:                    }
4934:
4935:                    if (getUseLocalSessionState()) {
4936:                        if (this .lowerCaseTableNames) {
4937:                            if (this .database.equalsIgnoreCase(catalog)) {
4938:                                return;
4939:                            }
4940:                        } else {
4941:                            if (this .database.equals(catalog)) {
4942:                                return;
4943:                            }
4944:                        }
4945:                    }
4946:
4947:                    String quotedId = this .dbmd.getIdentifierQuoteString();
4948:
4949:                    if ((quotedId == null) || quotedId.equals(" ")) {
4950:                        quotedId = "";
4951:                    }
4952:
4953:                    StringBuffer query = new StringBuffer("USE ");
4954:                    query.append(quotedId);
4955:                    query.append(catalog);
4956:                    query.append(quotedId);
4957:
4958:                    execSQL(null, query.toString(), -1, null,
4959:                            java.sql.ResultSet.TYPE_FORWARD_ONLY,
4960:                            java.sql.ResultSet.CONCUR_READ_ONLY, false,
4961:                            this .database, null, false);
4962:
4963:                    this .database = catalog;
4964:                }
4965:            }
4966:
4967:            /**
4968:             * @param failedOver
4969:             *            The failedOver to set.
4970:             */
4971:            public synchronized void setFailedOver(boolean flag) {
4972:                this .failedOver = flag;
4973:            }
4974:
4975:            /**
4976:             * Sets state for a failed-over connection
4977:             * 
4978:             * @throws SQLException
4979:             *             DOCUMENT ME!
4980:             */
4981:            private void setFailedOverState() throws SQLException {
4982:                if (getFailOverReadOnly()) {
4983:                    setReadOnlyInternal(true);
4984:                }
4985:
4986:                this .queriesIssuedFailedOver = 0;
4987:                this .failedOver = true;
4988:                this .masterFailTimeMillis = System.currentTimeMillis();
4989:            }
4990:
4991:            /**
4992:             * @see Connection#setHoldability(int)
4993:             */
4994:            public void setHoldability(int arg0) throws SQLException {
4995:                // do nothing
4996:            }
4997:
4998:            public void setInGlobalTx(boolean flag) {
4999:                this .isInGlobalTx = flag;
5000:            }
5001:
5002:            // exposed for testing
5003:            /**
5004:             * @param preferSlaveDuringFailover
5005:             *            The preferSlaveDuringFailover to set.
5006:             */
5007:            public void setPreferSlaveDuringFailover(boolean flag) {
5008:                this .preferSlaveDuringFailover = flag;
5009:            }
5010:
5011:            void setReadInfoMsgEnabled(boolean flag) {
5012:                this .readInfoMsg = flag;
5013:            }
5014:
5015:            /**
5016:             * You can put a connection in read-only mode as a hint to enable database
5017:             * optimizations <B>Note:</B> setReadOnly cannot be called while in the
5018:             * middle of a transaction
5019:             * 
5020:             * @param readOnlyFlag -
5021:             *            true enables read-only mode; false disables it
5022:             * @exception SQLException
5023:             *                if a database access error occurs
5024:             */
5025:            public void setReadOnly(boolean readOnlyFlag) throws SQLException {
5026:                checkClosed();
5027:
5028:                // Ignore calls to this method if we're failed over and
5029:                // we're configured to fail over read-only.
5030:                if (this .failedOver && getFailOverReadOnly() && !readOnlyFlag) {
5031:                    return;
5032:                }
5033:
5034:                setReadOnlyInternal(readOnlyFlag);
5035:            }
5036:
5037:            protected void setReadOnlyInternal(boolean readOnlyFlag)
5038:                    throws SQLException {
5039:                this .readOnly = readOnlyFlag;
5040:            }
5041:
5042:            /**
5043:             * @see Connection#setSavepoint()
5044:             */
5045:            public java.sql.Savepoint setSavepoint() throws SQLException {
5046:                MysqlSavepoint savepoint = new MysqlSavepoint();
5047:
5048:                setSavepoint(savepoint);
5049:
5050:                return savepoint;
5051:            }
5052:
5053:            private void setSavepoint(MysqlSavepoint savepoint)
5054:                    throws SQLException {
5055:
5056:                if (versionMeetsMinimum(4, 0, 14)
5057:                        || versionMeetsMinimum(4, 1, 1)) {
5058:                    synchronized (getMutex()) {
5059:                        checkClosed();
5060:
5061:                        StringBuffer savePointQuery = new StringBuffer(
5062:                                "SAVEPOINT ");
5063:                        savePointQuery.append('`');
5064:                        savePointQuery.append(savepoint.getSavepointName());
5065:                        savePointQuery.append('`');
5066:
5067:                        java.sql.Statement stmt = null;
5068:
5069:                        try {
5070:                            stmt = createStatement();
5071:
5072:                            stmt.executeUpdate(savePointQuery.toString());
5073:                        } finally {
5074:                            closeStatement(stmt);
5075:                        }
5076:                    }
5077:                } else {
5078:                    throw new NotImplemented();
5079:                }
5080:            }
5081:
5082:            /**
5083:             * @see Connection#setSavepoint(String)
5084:             */
5085:            public synchronized java.sql.Savepoint setSavepoint(String name)
5086:                    throws SQLException {
5087:                MysqlSavepoint savepoint = new MysqlSavepoint(name);
5088:
5089:                setSavepoint(savepoint);
5090:
5091:                return savepoint;
5092:            }
5093:
5094:            /**
5095:             * 
5096:             */
5097:            private void setSessionVariables() throws SQLException {
5098:                if (this .versionMeetsMinimum(4, 0, 0)
5099:                        && getSessionVariables() != null) {
5100:                    List variablesToSet = StringUtils.split(
5101:                            getSessionVariables(), ",", "\"'", "\"'", false);
5102:
5103:                    int numVariablesToSet = variablesToSet.size();
5104:
5105:                    java.sql.Statement stmt = null;
5106:
5107:                    try {
5108:                        stmt = getMetadataSafeStatement();
5109:
5110:                        for (int i = 0; i < numVariablesToSet; i++) {
5111:                            String variableValuePair = (String) variablesToSet
5112:                                    .get(i);
5113:
5114:                            if (variableValuePair.startsWith("@")) {
5115:                                stmt.executeUpdate("SET " + variableValuePair);
5116:                            } else {
5117:                                stmt.executeUpdate("SET SESSION "
5118:                                        + variableValuePair);
5119:                            }
5120:                        }
5121:                    } finally {
5122:                        if (stmt != null) {
5123:                            stmt.close();
5124:                        }
5125:                    }
5126:                }
5127:
5128:            }
5129:
5130:            /**
5131:             * DOCUMENT ME!
5132:             * 
5133:             * @param level
5134:             *            DOCUMENT ME!
5135:             * @throws SQLException
5136:             *             DOCUMENT ME!
5137:             */
5138:            public synchronized void setTransactionIsolation(int level)
5139:                    throws SQLException {
5140:                checkClosed();
5141:
5142:                if (this .hasIsolationLevels) {
5143:                    String sql = null;
5144:
5145:                    boolean shouldSendSet = false;
5146:
5147:                    if (getAlwaysSendSetIsolation()) {
5148:                        shouldSendSet = true;
5149:                    } else {
5150:                        if (level != this .isolationLevel) {
5151:                            shouldSendSet = true;
5152:                        }
5153:                    }
5154:
5155:                    if (getUseLocalSessionState()) {
5156:                        shouldSendSet = this .isolationLevel != level;
5157:                    }
5158:
5159:                    if (shouldSendSet) {
5160:                        switch (level) {
5161:                        case java.sql.Connection.TRANSACTION_NONE:
5162:                            throw SQLError
5163:                                    .createSQLException("Transaction isolation level "
5164:                                            + "NONE not supported by MySQL");
5165:
5166:                        case java.sql.Connection.TRANSACTION_READ_COMMITTED:
5167:                            sql = "SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED";
5168:
5169:                            break;
5170:
5171:                        case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:
5172:                            sql = "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
5173:
5174:                            break;
5175:
5176:                        case java.sql.Connection.TRANSACTION_REPEATABLE_READ:
5177:                            sql = "SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ";
5178:
5179:                            break;
5180:
5181:                        case java.sql.Connection.TRANSACTION_SERIALIZABLE:
5182:                            sql = "SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE";
5183:
5184:                            break;
5185:
5186:                        default:
5187:                            throw SQLError
5188:                                    .createSQLException(
5189:                                            "Unsupported transaction "
5190:                                                    + "isolation level '"
5191:                                                    + level + "'",
5192:                                            SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
5193:                        }
5194:
5195:                        execSQL(null, sql, -1, null,
5196:                                java.sql.ResultSet.TYPE_FORWARD_ONLY,
5197:                                java.sql.ResultSet.CONCUR_READ_ONLY, false,
5198:                                this .database, null, false);
5199:
5200:                        this .isolationLevel = level;
5201:                    }
5202:                } else {
5203:                    throw SQLError
5204:                            .createSQLException(
5205:                                    "Transaction Isolation Levels are "
5206:                                            + "not supported on MySQL versions older than 3.23.36.",
5207:                                    SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
5208:                }
5209:            }
5210:
5211:            /**
5212:             * JDBC 2.0 Install a type-map object as the default type-map for this
5213:             * connection
5214:             * 
5215:             * @param map
5216:             *            the type mapping
5217:             * @throws SQLException
5218:             *             if a database error occurs.
5219:             */
5220:            public synchronized void setTypeMap(java.util.Map map)
5221:                    throws SQLException {
5222:                this .typeMap = map;
5223:            }
5224:
5225:            private void setupServerForTruncationChecks() throws SQLException {
5226:                if (getJdbcCompliantTruncation()) {
5227:                    if (versionMeetsMinimum(5, 0, 2)) {
5228:                        String currentSqlMode = (String) this .serverVariables
5229:                                .get("sql_mode");
5230:
5231:                        boolean strictTransTablesIsSet = StringUtils
5232:                                .indexOfIgnoreCase(currentSqlMode,
5233:                                        "STRICT_TRANS_TABLES") != -1;
5234:
5235:                        if (currentSqlMode == null
5236:                                || currentSqlMode.length() == 0
5237:                                || !strictTransTablesIsSet) {
5238:                            StringBuffer commandBuf = new StringBuffer(
5239:                                    "SET sql_mode='");
5240:
5241:                            if (currentSqlMode != null
5242:                                    && currentSqlMode.length() > 0) {
5243:                                commandBuf.append(currentSqlMode);
5244:                                commandBuf.append(",");
5245:                            }
5246:
5247:                            commandBuf.append("STRICT_TRANS_TABLES'");
5248:
5249:                            execSQL(null, commandBuf.toString(), -1, null,
5250:                                    java.sql.ResultSet.TYPE_FORWARD_ONLY,
5251:                                    java.sql.ResultSet.CONCUR_READ_ONLY, false,
5252:                                    this .database, null, false);
5253:
5254:                            setJdbcCompliantTruncation(false); // server's handling this for us now
5255:                        } else if (strictTransTablesIsSet) {
5256:                            // We didn't set it, but someone did, so we piggy back on it
5257:                            setJdbcCompliantTruncation(false); // server's handling this for us now
5258:                        }
5259:
5260:                    }
5261:                }
5262:            }
5263:
5264:            /**
5265:             * Should we try to connect back to the master? We try when we've been
5266:             * failed over >= this.secondsBeforeRetryMaster _or_ we've issued >
5267:             * this.queriesIssuedFailedOver
5268:             * 
5269:             * @return DOCUMENT ME!
5270:             */
5271:            private boolean shouldFallBack() {
5272:                long secondsSinceFailedOver = (System.currentTimeMillis() - this .masterFailTimeMillis) / 1000;
5273:
5274:                // Done this way so we can set a condition in the debugger
5275:                boolean tryFallback = ((secondsSinceFailedOver >= getSecondsBeforeRetryMaster()) || (this .queriesIssuedFailedOver >= getQueriesBeforeRetryMaster()));
5276:
5277:                return tryFallback;
5278:            }
5279:
5280:            /**
5281:             * Used by MiniAdmin to shutdown a MySQL server
5282:             * 
5283:             * @throws SQLException
5284:             *             if the command can not be issued.
5285:             */
5286:            public void shutdownServer() throws SQLException {
5287:                try {
5288:                    this .io.sendCommand(MysqlDefs.SHUTDOWN, null, null, false,
5289:                            null);
5290:                } catch (Exception ex) {
5291:                    throw SQLError.createSQLException("Unhandled exception '"
5292:                            + ex.toString() + "'",
5293:                            SQLError.SQL_STATE_GENERAL_ERROR);
5294:                }
5295:            }
5296:
5297:            /**
5298:             * DOCUMENT ME!
5299:             * 
5300:             * @return DOCUMENT ME!
5301:             */
5302:            public boolean supportsIsolationLevel() {
5303:                return this .hasIsolationLevels;
5304:            }
5305:
5306:            /**
5307:             * DOCUMENT ME!
5308:             * 
5309:             * @return DOCUMENT ME!
5310:             */
5311:            public boolean supportsQuotedIdentifiers() {
5312:                return this .hasQuotedIdentifiers;
5313:            }
5314:
5315:            /**
5316:             * DOCUMENT ME!
5317:             * 
5318:             * @return DOCUMENT ME!
5319:             */
5320:            public boolean supportsTransactions() {
5321:                return this .transactionsSupported;
5322:            }
5323:
5324:            /**
5325:             * Remove the given statement from the list of open statements
5326:             * 
5327:             * @param stmt
5328:             *            the Statement instance to remove
5329:             */
5330:            void unregisterStatement(StatementImpl stmt) {
5331:                if (this .openStatements != null) {
5332:                    synchronized (this .openStatements) {
5333:                        this .openStatements.remove(stmt);
5334:                    }
5335:                }
5336:            }
5337:
5338:            /**
5339:             * Called by statements on their .close() to let the connection know when it
5340:             * is safe to set the connection back to 'default' row limits.
5341:             * 
5342:             * @param stmt
5343:             *            the statement releasing it's max-rows requirement
5344:             * @throws SQLException
5345:             *             if a database error occurs issuing the statement that sets
5346:             *             the limit default.
5347:             */
5348:            void unsetMaxRows(StatementImpl stmt) throws SQLException {
5349:                synchronized (this .mutex) {
5350:                    if (this .statementsUsingMaxRows != null) {
5351:                        Object found = this .statementsUsingMaxRows.remove(stmt);
5352:
5353:                        if ((found != null)
5354:                                && (this .statementsUsingMaxRows.size() == 0)) {
5355:                            execSQL(null,
5356:                                    "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1,
5357:                                    null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
5358:                                    java.sql.ResultSet.CONCUR_READ_ONLY, false,
5359:                                    this .database, null, false);
5360:
5361:                            this .maxRowsChanged = false;
5362:                        }
5363:                    }
5364:                }
5365:            }
5366:
5367:            boolean useAnsiQuotedIdentifiers() {
5368:                return this .useAnsiQuotes;
5369:            }
5370:
5371:            /**
5372:             * Has maxRows() been set?
5373:             * 
5374:             * @return DOCUMENT ME!
5375:             */
5376:            boolean useMaxRows() {
5377:                synchronized (this .mutex) {
5378:                    return this .maxRowsChanged;
5379:                }
5380:            }
5381:
5382:            public boolean versionMeetsMinimum(int major, int minor,
5383:                    int subminor) throws SQLException {
5384:                checkClosed();
5385:
5386:                return this .io.versionMeetsMinimum(major, minor, subminor);
5387:            }
5388:
5389:            /**
5390:             * Returns cached metadata (or null if not cached) for the given query,
5391:             * which must match _exactly_.	 
5392:             *  
5393:             * This method is synchronized by the caller on getMutex(), so if
5394:             * calling this method from internal code in the driver, make sure it's
5395:             * synchronized on the mutex that guards communication with the server.
5396:             * 
5397:             * @param sql
5398:             *            the query that is the key to the cache
5399:             * 
5400:             * @return metadata cached for the given SQL, or none if it doesn't
5401:             *                  exist.
5402:             */
5403:            protected CachedResultSetMetaData getCachedMetaData(String sql) {
5404:                if (this .resultSetMetadataCache != null) {
5405:                    synchronized (this .resultSetMetadataCache) {
5406:                        return (CachedResultSetMetaData) this .resultSetMetadataCache
5407:                                .get(sql);
5408:                    }
5409:                }
5410:
5411:                return null; // no cache exists
5412:            }
5413:
5414:            /**
5415:             * Caches CachedResultSetMetaData that has been placed in the cache using
5416:             * the given SQL as a key.
5417:             * 
5418:             * This method is synchronized by the caller on getMutex(), so if
5419:             * calling this method from internal code in the driver, make sure it's
5420:             * synchronized on the mutex that guards communication with the server.
5421:             * 
5422:             * @param sql the query that the metadata pertains too.
5423:             * @param cachedMetaData metadata (if it exists) to populate the cache.
5424:             * @param resultSet the result set to retreive metadata from, or apply to.
5425:             *
5426:             * @throws SQLException
5427:             */
5428:            protected void initializeResultsMetadataFromCache(String sql,
5429:                    CachedResultSetMetaData cachedMetaData,
5430:                    ResultSetInternalMethods resultSet) throws SQLException {
5431:
5432:                if (cachedMetaData == null) {
5433:
5434:                    // read from results
5435:                    cachedMetaData = new CachedResultSetMetaData();
5436:
5437:                    // assume that users will use named-based
5438:                    // lookups
5439:                    resultSet.buildIndexMapping();
5440:                    resultSet.initializeWithMetadata();
5441:
5442:                    if (resultSet instanceof  UpdatableResultSet) {
5443:                        ((UpdatableResultSet) resultSet).checkUpdatability();
5444:                    }
5445:
5446:                    resultSet.populateCachedMetaData(cachedMetaData);
5447:
5448:                    this .resultSetMetadataCache.put(sql, cachedMetaData);
5449:                } else {
5450:                    resultSet.initializeFromCachedMetaData(cachedMetaData);
5451:                    resultSet.initializeWithMetadata();
5452:
5453:                    if (resultSet instanceof  UpdatableResultSet) {
5454:                        ((UpdatableResultSet) resultSet).checkUpdatability();
5455:                    }
5456:                }
5457:            }
5458:
5459:            /**
5460:             * Returns the comment that will be prepended to all statements
5461:             * sent to the server.
5462:             * 
5463:             * @return the comment that will be prepended to all statements
5464:             * sent to the server.
5465:             */
5466:            public String getStatementComment() {
5467:                return this .statementComment;
5468:            }
5469:
5470:            /**
5471:             * Sets the comment that will be prepended to all statements
5472:             * sent to the server. Do not use slash-star or star-slash tokens 
5473:             * in the comment as these will be added by the driver itself.
5474:             * 
5475:             * @param comment  the comment that will be prepended to all statements
5476:             * sent to the server.
5477:             */
5478:            public void setStatementComment(String comment) {
5479:                this.statementComment = comment;
5480:            }
5481:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.