Connection.java
上传用户:sxlinghang
上传日期:2022-07-20
资源大小:1405k
文件大小:130k
源码类别:

数据库编程

开发平台:

Java

  1. /*
  2.    Copyright (C) 2002 MySQL AB
  3.       This program is free software; you can redistribute it and/or modify
  4.       it under the terms of the GNU General Public License as published by
  5.       the Free Software Foundation; either version 2 of the License, or
  6.       (at your option) any later version.
  7.       This program is distributed in the hope that it will be useful,
  8.       but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.       GNU General Public License for more details.
  11.       You should have received a copy of the GNU General Public License
  12.       along with this program; if not, write to the Free Software
  13.       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  14.  */
  15. package com.mysql.jdbc;
  16. import java.io.IOException;
  17. import java.io.InputStream;
  18. import java.io.Reader;
  19. import java.io.UnsupportedEncodingException;
  20. import java.math.BigDecimal;
  21. import java.net.URL;
  22. import java.sql.Clob;
  23. import java.sql.Date;
  24. import java.sql.ParameterMetaData;
  25. import java.sql.Ref;
  26. import java.sql.SQLException;
  27. import java.sql.Savepoint;
  28. import java.sql.Time;
  29. import java.sql.Timestamp;
  30. import java.util.ArrayList;
  31. import java.util.Calendar;
  32. import java.util.HashMap;
  33. import java.util.Iterator;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.Properties;
  37. import java.util.TimeZone;
  38. /**
  39.  * A Connection represents a session with a specific database.  Within the
  40.  * context of a Connection, SQL statements are executed and results are
  41.  * returned.
  42.  * 
  43.  * <P>
  44.  * A Connection's database is able to provide information describing its
  45.  * tables, its supported SQL grammar, its stored procedures, the capabilities
  46.  * of this connection, etc.  This information is obtained with the getMetaData
  47.  * method.
  48.  * </p>
  49.  *
  50.  * @author Mark Matthews
  51.  * @version $Id: Connection.java,v 1.31.2.55 2004/02/13 22:33:50 mmatthew Exp $
  52.  *
  53.  * @see java.sql.Connection
  54.  */
  55. public class Connection implements java.sql.Connection {
  56.     // The command used to "ping" the database.
  57.     // Newer versions of MySQL server have a ping() command,
  58.     // but this works for everything
  59.     private static final String PING_COMMAND = "SELECT 1";
  60.     /**
  61.      * Map mysql transaction isolation level name to
  62.      * java.sql.Connection.TRANSACTION_XXX
  63.      */
  64.     private static Map mapTransIsolationName2Value = null;
  65.     /**
  66.      * The mapping between MySQL charset names and Java charset names.
  67.      * Initialized by loadCharacterSetMapping()
  68.      */
  69.     private static Map charsetMap;
  70.     /** Table of multi-byte charsets. Initialized by loadCharacterSetMapping() */
  71.     private static Map multibyteCharsetsMap;
  72.     /** Default socket factory classname */
  73.     private static final String DEFAULT_SOCKET_FACTORY = StandardSocketFactory.class
  74.         .getName();
  75.     static {
  76.         loadCharacterSetMapping();
  77.         mapTransIsolationName2Value = new HashMap(8);
  78.         mapTransIsolationName2Value.put("READ-UNCOMMITED",
  79.             new Integer(TRANSACTION_READ_UNCOMMITTED));
  80.         mapTransIsolationName2Value.put("READ-UNCOMMITTED",
  81.             new Integer(TRANSACTION_READ_UNCOMMITTED));
  82.         mapTransIsolationName2Value.put("READ-COMMITTED",
  83.             new Integer(TRANSACTION_READ_COMMITTED));
  84.         mapTransIsolationName2Value.put("REPEATABLE-READ",
  85.             new Integer(TRANSACTION_REPEATABLE_READ));
  86.         mapTransIsolationName2Value.put("SERIALIZABLE",
  87.             new Integer(TRANSACTION_SERIALIZABLE));
  88.     }
  89.     /**
  90.      * Marker for character set converter not being available (not written,
  91.      * multibyte, etc)  Used to prevent multiple instantiation requests.
  92.      */
  93.     private final static Object CHARSET_CONVERTER_NOT_AVAILABLE_MARKER = new Object();
  94.     /** Internal DBMD to use for various database-version specific features */
  95.     private DatabaseMetaData dbmd = null;
  96.     /** The list of host(s) to try and connect to */
  97.     private List hostList = null;
  98.     /** A map of SQL to parsed prepared statement parameters. */
  99.     private Map cachedPreparedStatementParams;
  100.     /**
  101.      * Holds cached mappings to charset converters to avoid static
  102.      * synchronization and at the same time save memory (each charset
  103.      * converter takes approx 65K of static data).
  104.      */
  105.     private Map charsetConverterMap = new HashMap(CharsetMapping.JAVA_TO_MYSQL_CHARSET_MAP
  106.             .size());
  107.     /** A map of statements that have had setMaxRows() called on them */
  108.     private Map statementsUsingMaxRows;
  109.     /**
  110.      * The type map for UDTs (not implemented, but used by some third-party
  111.      * vendors, most notably IBM WebSphere)
  112.      */
  113.     private Map typeMap;
  114.     /** The I/O abstraction interface (network conn to MySQL server */
  115.     private MysqlIO io = null;
  116.     /** Mutex */
  117.     private final Object mutex = new Object();
  118.     /** The map of server variables that we retrieve at connection init. */
  119.     private Map serverVariables = null;
  120.     /** The driver instance that created us */
  121.     private NonRegisteringDriver myDriver;
  122.     /** Properties for this connection specified by user */
  123.     private Properties props = null;
  124.     /** The database we're currently using (called Catalog in JDBC terms). */
  125.     private String database = null;
  126.     /** If we're doing unicode character conversions, what encoding do we use? */
  127.     private String encoding = null;
  128.     /** The hostname we're connected to */
  129.     private String host = null;
  130.     /** The JDBC URL we're using */
  131.     private String myURL = null;
  132.     /** What does MySQL call this encoding? */
  133.     private String mysqlEncodingName = null;
  134.     private String negativeInfinityRep = MysqlDefs.MIN_DOUBLE_VAL_STRING;
  135.     private String notANumberRep = MysqlDefs.NAN_VAL_STRING;
  136.     /** The password we used */
  137.     private String password = null;
  138.     private String positiveInfinityRep = MysqlDefs.MAX_DOUBLE_VAL_STRING;
  139.     /** Classname for socket factory */
  140.     private String socketFactoryClassName = null;
  141.     /** The user we're connected as */
  142.     private String user = null;
  143.     /** Where was the connection _explicitly_ closed by the application? */
  144.     private Throwable explicitCloseLocation;
  145.     /** If the connection was forced closed, why was it  forced closed? */
  146.     private Throwable forcedCloseReason;
  147.     private TimeZone defaultTimeZone;
  148.     /** The timezone of the server */
  149.     private TimeZone serverTimezone = null;
  150.     /** Allow LOAD LOCAL INFILE (defaults to true) */
  151.     private boolean allowLoadLocalInfile = true;
  152.     /** Should we clear the input stream each query? */
  153.     private boolean alwaysClearStream = false;
  154.     /** Are we in autoCommit mode? */
  155.     private boolean autoCommit = true;
  156.     /** SHould we cache the parsing of prepared statements? */
  157.     private boolean cachePreparedStatements = false;
  158.     /** Should we capitalize mysql types */
  159.     private boolean capitalizeDBMDTypes = false;
  160.     /** Should we clobber streaming results on new queries, or issue an error? */
  161.     private boolean clobberStreamingResults = false;
  162.     /**
  163.      * Should we continue processing batch commands if one fails. The JDBC spec
  164.      * allows either way, so we let the user choose
  165.      */
  166.     private boolean continueBatchOnError = true;
  167.     /** Should we do unicode character conversions? */
  168.     private boolean doUnicode = false;
  169.     /** Are we failed-over to a non-master host */
  170.     private boolean failedOver = false;
  171.     /** Does the server suuport isolation levels? */
  172.     private boolean hasIsolationLevels = false;
  173.     /** Does this version of MySQL support quoted identifiers? */
  174.     private boolean hasQuotedIdentifiers = false;
  175.     //
  176.     // This is for the high availability :) routines
  177.     //
  178.     private boolean highAvailability = false;
  179.     /** Ignore non-transactional table warning for rollback? */
  180.     private boolean ignoreNonTxTables = false;
  181.     /** Has this connection been closed? */
  182.     private boolean isClosed = true;
  183.     /** Should we tell MySQL that we're an interactive client? */
  184.     private boolean isInteractiveClient = false;
  185.     /** Is the server configured to use lower-case table names only? */
  186.     private boolean lowerCaseTableNames = false;
  187.     /** Has the max-rows setting been changed from the default? */
  188.     private boolean maxRowsChanged = false;
  189.     private boolean negativeInfinityRepIsClipped = true;
  190.     private boolean notANumberRepIsClipped = true;
  191.     /** Do we expose sensitive information in exception and error messages? */
  192.     private boolean paranoid = false;
  193.     /** Should we do 'extra' sanity checks? */
  194.     private boolean pedantic = false;
  195.     private boolean positiveInfinityRepIsClipped = true;
  196.     /** Should we retrieve 'info' messages from the server? */
  197.     private boolean readInfoMsg = false;
  198.     /** Are we in read-only mode? */
  199.     private boolean readOnly = false;
  200.     /**
  201.      * If autoReconnect == true, should we attempt to reconnect at transaction
  202.      * boundaries?
  203.      */
  204.     private boolean reconnectAtTxEnd = false;
  205.     /** Do we relax the autoCommit semantics? (For enhydra, for example) */
  206.     private boolean relaxAutoCommit = false;
  207.     /** Do we need to correct endpoint rounding errors */
  208.     private boolean strictFloatingPoint = false;
  209.     /** Do we check all keys for updatable result sets? */
  210.     private boolean strictUpdates = true;
  211.     /** Are transactions supported by the MySQL server we are connected to? */
  212.     private boolean transactionsSupported = false;
  213.     /** Has ANSI_QUOTES been enabled on the server? */
  214.     private boolean useAnsiQuotes = false;
  215.     /** Should we use compression? */
  216.     private boolean useCompression = false;
  217.     /** Can we use the "ping" command rather than a query? */
  218.     private boolean useFastPing = false;
  219.     /** Should we tack on hostname in DBMD.getTable/ColumnPrivileges()? */
  220.     private boolean useHostsInPrivileges = true;
  221.     /** Should we use SSL? */
  222.     private boolean useSSL = false;
  223.     /**
  224.      * Should we use stream lengths in prepared statements? (true by default ==
  225.      * JDBC compliant)
  226.      */
  227.     private boolean useStreamLengthsInPrepStmts = true;
  228.     /** Should we use timezone information? */
  229.     private boolean useTimezone = false;
  230.     /** Should we return PreparedStatements for UltraDev's stupid bug? */
  231.     private boolean useUltraDevWorkAround = false;
  232.     private boolean useUnbufferedInput = true;
  233.     private double initialTimeout = 2.0D;
  234.     /** How many hosts are in the host list? */
  235.     private int hostListSize = 0;
  236.     /** isolation level */
  237.     private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
  238.     /**
  239.      * The largest packet we can send (changed once we know what the server
  240.      * supports, we get this at connection init).
  241.      */
  242.     private int maxAllowedPacket = 65536;
  243.     private int maxReconnects = 3;
  244.     /**
  245.      * The max rows that a result set can contain. Defaults to -1, which
  246.      * according to the JDBC spec means "all".
  247.      */
  248.     private int maxRows = -1;
  249.     private int netBufferLength = 16384;
  250.     /** The port number we're connected to (defaults to 3306) */
  251.     private int port = 3306;
  252.     /**
  253.      * If prepared statement caching is enabled, what should the threshold
  254.      * length of the SQL to prepare should be in order to _not_ cache?
  255.      */
  256.     private int preparedStatementCacheMaxSqlSize = 256;
  257.     /** If prepared statement caching is enabled, how many should we cache? */
  258.     private int preparedStatementCacheSize = 25;
  259.     /**
  260.      * How many queries should we wait before we try to re-connect to the
  261.      * master, when we are failing over to replicated hosts Defaults to 50
  262.      */
  263.     private int queriesBeforeRetryMaster = 50;
  264.     /** What should we set the socket timeout to? */
  265.     private int socketTimeout = 0; // infinite
  266.     /** When did the last query finish? */
  267.     private long lastQueryFinishedTime = 0;
  268.     /** When did the master fail? */
  269.     private long masterFailTimeMillis = 0L;
  270.     /** Number of queries we've issued since the master failed */
  271.     private long queriesIssuedFailedOver = 0;
  272.     /**
  273.      * How many seconds should we wait before retrying to connect to the master
  274.      * if failed over? We fall back when either queriesBeforeRetryMaster or
  275.      * secondsBeforeRetryMaster is reached.
  276.      */
  277.     private long secondsBeforeRetryMaster = 30L;
  278.     /**
  279.      * Creates a connection to a MySQL Server.
  280.      *
  281.      * @param host the hostname of the database server
  282.      * @param port the port number the server is listening on
  283.      * @param info a Properties[] list holding the user and password
  284.      * @param database the database to connect to
  285.      * @param url the URL of the connection
  286.      * @param d the Driver instantation of the connection
  287.      *
  288.      * @exception java.sql.SQLException if a database access error occurs
  289.      * @throws SQLException DOCUMENT ME!
  290.      */
  291.     Connection(String host, int port, Properties info, String database,
  292.         String url, NonRegisteringDriver d) throws java.sql.SQLException {
  293.         if (Driver.TRACE) {
  294.             Object[] args = { host, new Integer(port), info, database, url, d };
  295.             Debug.methodCall(this, "constructor", args);
  296.         }
  297.         this.defaultTimeZone = TimeZone.getDefault();
  298.         this.serverVariables = new HashMap();
  299.         if (host == null) {
  300.             this.host = "localhost";
  301.             hostList = new ArrayList();
  302.             hostList.add(this.host);
  303.         } else if (host.indexOf(",") != -1) {
  304.             // multiple hosts separated by commas (failover)
  305.             hostList = StringUtils.split(host, ",", true);
  306.         } else {
  307.             this.host = host;
  308.             hostList = new ArrayList();
  309.             hostList.add(this.host);
  310.         }
  311.         hostListSize = hostList.size();
  312.         this.port = port;
  313.         if (database == null) {
  314.             throw new SQLException("Malformed URL '" + url + "'.",
  315.                 SQLError.SQL_STATE_GENERAL_ERROR);
  316.         }
  317.         this.database = database;
  318.         this.myURL = url;
  319.         this.myDriver = d;
  320.         this.user = info.getProperty("user");
  321.         this.password = info.getProperty("password");
  322.         if ((this.user == null) || this.user.equals("")) {
  323.             this.user = "nobody";
  324.         }
  325.         if (this.password == null) {
  326.             this.password = "";
  327.         }
  328.         this.props = info;
  329.         initializeDriverProperties(info);
  330.         if (Driver.DEBUG) {
  331.             System.out.println("Connect: " + this.user + " to " + this.database);
  332.         }
  333.         try {
  334.             createNewIO(false);
  335.             this.dbmd = new DatabaseMetaData(this, this.database);
  336.         } catch (java.sql.SQLException ex) {
  337.             cleanup(ex);
  338.             // don't clobber SQL exceptions
  339.             throw ex;
  340.         } catch (Exception ex) {
  341.             cleanup(ex);
  342.             StringBuffer mesg = new StringBuffer();
  343.             if (!useParanoidErrorMessages()) {
  344.                 mesg.append("Cannot connect to MySQL server on ");
  345.                 mesg.append(this.host);
  346.                 mesg.append(":");
  347.                 mesg.append(this.port);
  348.                 mesg.append(".nn");
  349.                 mesg.append("Make sure that there is a MySQL server ");
  350.                 mesg.append("running on the machine/port you are trying ");
  351.                 mesg.append(
  352.                     "to connect to and that the machine this software is "
  353.                     + "running on ");
  354.                 mesg.append("is able to connect to this host/port "
  355.                     + "(i.e. not firewalled). ");
  356.                 mesg.append(
  357.                     "Also make sure that the server has not been started "
  358.                     + "with the --skip-networking ");
  359.                 mesg.append("flag.nn");
  360.             } else {
  361.                 mesg.append("Unable to connect to database.");
  362.             }
  363.             mesg.append("Underlying exception: nn");
  364.             mesg.append(ex.getClass().getName());
  365.             throw new java.sql.SQLException(mesg.toString(),
  366.                 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE);
  367.         }
  368.     }
  369.     /**
  370.      * If a connection is in auto-commit mode, than all its SQL statements will
  371.      * be executed and committed as individual transactions.  Otherwise, its
  372.      * SQL statements are grouped into transactions that are terminated by
  373.      * either commit() or rollback().  By default, new connections are in
  374.      * auto- commit mode.  The commit occurs when the statement completes or
  375.      * the next execute occurs, whichever comes first.  In the case of
  376.      * statements returning a ResultSet, the statement completes when the last
  377.      * row of the ResultSet has been retrieved or the ResultSet has been
  378.      * closed.  In advanced cases, a single statement may return multiple
  379.      * results as well as output parameter values.  Here the commit occurs
  380.      * when all results and output param values have been retrieved.
  381.      * 
  382.      * <p>
  383.      * <b>Note:</b> MySQL does not support transactions, so this method is a
  384.      * no-op.
  385.      * </p>
  386.      *
  387.      * @param autoCommit - true enables auto-commit; false disables it
  388.      *
  389.      * @exception java.sql.SQLException if a database access error occurs
  390.      * @throws SQLException DOCUMENT ME!
  391.      */
  392.     public void setAutoCommit(boolean autoCommit) throws java.sql.SQLException {
  393.         if (Driver.TRACE) {
  394.             Object[] args = { new Boolean(autoCommit) };
  395.             Debug.methodCall(this, "setAutoCommit", args);
  396.         }
  397.         checkClosed();
  398.         if (this.transactionsSupported) {
  399.             // this internal value must be set first as failover depends on it
  400.             // being set to true to fail over (which is done by most
  401.             // app servers and connection pools at the end of
  402.             // a transaction), and the driver issues an implicit set
  403.             // based on this value when it (re)-connects to a server
  404.             // so the value holds across connections
  405.             //
  406.             this.autoCommit = autoCommit;
  407.             //
  408.             // This is to catch the 'edge' case of
  409.             // autoCommit going from true -> false
  410.             //
  411.             if ((this.highAvailability || this.failedOver) && !this.autoCommit) {
  412.                 pingAndReconnect(true);
  413.             }
  414.             String sql = "SET autocommit=" + (autoCommit ? "1" : "0");
  415.             execSQL(sql, -1, this.database);
  416.         } else {
  417.             if ((autoCommit == false) && (this.relaxAutoCommit == false)) {
  418.                 throw new SQLException("MySQL Versions Older than 3.23.15 "
  419.                     + "do not support transactions",
  420.                     SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
  421.             } else {
  422.                 this.autoCommit = autoCommit;
  423.             }
  424.         }
  425.         return;
  426.     }
  427.     /**
  428.      * gets the current auto-commit state
  429.      *
  430.      * @return Current state of the auto-commit mode
  431.      *
  432.      * @exception java.sql.SQLException (why?)
  433.      *
  434.      * @see setAutoCommit
  435.      */
  436.     public boolean getAutoCommit() throws java.sql.SQLException {
  437.         if (Driver.TRACE) {
  438.             Object[] args = new Object[0];
  439.             Debug.methodCall(this, "getAutoCommit", args);
  440.             Debug.returnValue(this, "getAutoCommit",
  441.                 new Boolean(this.autoCommit));
  442.         }
  443.         return this.autoCommit;
  444.     }
  445.     /**
  446.      * A sub-space of this Connection's database may be selected by setting a
  447.      * catalog name.  If the driver does not support catalogs, it will
  448.      * silently ignore this request
  449.      * 
  450.      * <p>
  451.      * <b>Note:</b> MySQL's notion of catalogs are individual databases.
  452.      * </p>
  453.      *
  454.      * @param catalog the database for this connection to use
  455.      *
  456.      * @throws java.sql.SQLException if a database access error occurs
  457.      */
  458.     public void setCatalog(String catalog) throws java.sql.SQLException {
  459.         if (Driver.TRACE) {
  460.             Object[] args = { catalog };
  461.             Debug.methodCall(this, "setCatalog", args);
  462.         }
  463.         checkClosed();
  464.         String quotedId = this.dbmd.getIdentifierQuoteString();
  465.         if ((quotedId == null) || quotedId.equals(" ")) {
  466.             quotedId = "";
  467.         }
  468.         StringBuffer query = new StringBuffer("USE ");
  469.         query.append(quotedId);
  470.         query.append(catalog);
  471.         query.append(quotedId);
  472.         execSQL(query.toString(), -1, catalog);
  473.         this.database = catalog;
  474.     }
  475.     /**
  476.      * Return the connections current catalog name, or null if no catalog name
  477.      * is set, or we dont support catalogs.
  478.      * 
  479.      * <p>
  480.      * <b>Note:</b> MySQL's notion of catalogs are individual databases.
  481.      * </p>
  482.      *
  483.      * @return the current catalog name or null
  484.      *
  485.      * @exception java.sql.SQLException if a database access error occurs
  486.      */
  487.     public String getCatalog() throws java.sql.SQLException {
  488.         if (Driver.TRACE) {
  489.             Object[] args = new Object[0];
  490.             Debug.methodCall(this, "getCatalog", args);
  491.             Debug.returnValue(this, "getCatalog", this.database);
  492.         }
  493.         return this.database;
  494.     }
  495.     /**
  496.      * Returns whether we clobber streaming results on new queries, or issue an
  497.      * error?
  498.      *
  499.      * @return true if we should implicitly close streaming result sets upon
  500.      *         receiving a new query
  501.      */
  502.     public boolean getClobberStreamingResults() {
  503.         return this.clobberStreamingResults;
  504.     }
  505.     /**
  506.      * DOCUMENT ME!
  507.      *
  508.      * @return DOCUMENT ME!
  509.      */
  510.     public boolean isClosed() {
  511.         if (Driver.TRACE) {
  512.             Object[] args = new Object[0];
  513.             Debug.methodCall(this, "isClosed", args);
  514.             Debug.returnValue(this, "isClosed", new Boolean(this.isClosed));
  515.         }
  516.         return this.isClosed;
  517.     }
  518.     /**
  519.      * Returns the character encoding for this Connection
  520.      *
  521.      * @return the character encoding for this connection.
  522.      */
  523.     public String getEncoding() {
  524.         return this.encoding;
  525.     }
  526.     /**
  527.      * @see Connection#setHoldability(int)
  528.      */
  529.     public void setHoldability(int arg0) throws SQLException {
  530.         // do nothing
  531.     }
  532.     /**
  533.      * @see Connection#getHoldability()
  534.      */
  535.     public int getHoldability() throws SQLException {
  536.         return ResultSet.CLOSE_CURSORS_AT_COMMIT;
  537.     }
  538.     /**
  539.      * NOT JDBC-Compliant, but clients can use this method to determine how
  540.      * long this connection has been idle. This time (reported in
  541.      * milliseconds) is updated once a query has completed.
  542.      *
  543.      * @return number of ms that this connection has been idle, 0 if the driver
  544.      *         is busy retrieving results.
  545.      */
  546.     public long getIdleFor() {
  547.         if (this.lastQueryFinishedTime == 0) {
  548.             return 0;
  549.         } else {
  550.             long now = System.currentTimeMillis();
  551.             long idleTime = now - this.lastQueryFinishedTime;
  552.             return idleTime;
  553.         }
  554.     }
  555.     /**
  556.      * Should we tell MySQL that we're an interactive client
  557.      *
  558.      * @return true if isInteractiveClient was set to true.
  559.      */
  560.     public boolean isInteractiveClient() {
  561.         return isInteractiveClient;
  562.     }
  563.     /**
  564.      * A connection's database is able to provide information describing its
  565.      * tables, its supported SQL grammar, its stored procedures, the
  566.      * capabilities of this connection, etc.  This information is made
  567.      * available through a DatabaseMetaData object.
  568.      *
  569.      * @return a DatabaseMetaData object for this connection
  570.      *
  571.      * @exception java.sql.SQLException if a database access error occurs
  572.      */
  573.     public java.sql.DatabaseMetaData getMetaData() throws java.sql.SQLException {
  574.         checkClosed();
  575.         return new DatabaseMetaData(this, this.database);
  576.     }
  577.     /**
  578.      * DOCUMENT ME!
  579.      *
  580.      * @return
  581.      */
  582.     public String getNegativeInfinityRep() {
  583.         return negativeInfinityRep;
  584.     }
  585.     /**
  586.      * DOCUMENT ME!
  587.      *
  588.      * @return
  589.      */
  590.     public boolean isNegativeInfinityRepIsClipped() {
  591.         return negativeInfinityRepIsClipped;
  592.     }
  593.     /**
  594.      * DOCUMENT ME!
  595.      *
  596.      * @return
  597.      */
  598.     public String getNotANumberRep() {
  599.         return notANumberRep;
  600.     }
  601.     /**
  602.      * DOCUMENT ME!
  603.      *
  604.      * @return
  605.      */
  606.     public boolean isNotANumberRepIsClipped() {
  607.         return notANumberRepIsClipped;
  608.     }
  609.     /**
  610.      * DOCUMENT ME!
  611.      *
  612.      * @return
  613.      */
  614.     public String getPositiveInfinityRep() {
  615.         return positiveInfinityRep;
  616.     }
  617.     /**
  618.      * DOCUMENT ME!
  619.      *
  620.      * @return
  621.      */
  622.     public boolean isPositiveInfinityRepIsClipped() {
  623.         return positiveInfinityRepIsClipped;
  624.     }
  625.     /**
  626.      * Should the driver do profiling?
  627.      *
  628.      * @param flag set to true to enable profiling.
  629.      *
  630.      * @throws SQLException if the connection is closed.
  631.      */
  632.     public void setProfileSql(boolean flag) throws SQLException {
  633.         // For re-connection
  634.         this.props.setProperty("profileSql", String.valueOf(flag));
  635.         getIO().setProfileSql(flag);
  636.     }
  637.     /**
  638.      * You can put a connection in read-only mode as a hint to enable database
  639.      * optimizations <B>Note:</B> setReadOnly cannot be called while in the
  640.      * middle of a transaction
  641.      *
  642.      * @param readOnly - true enables read-only mode; false disables it
  643.      *
  644.      * @exception java.sql.SQLException if a database access error occurs
  645.      */
  646.     public void setReadOnly(boolean readOnly) throws java.sql.SQLException {
  647.         if (Driver.TRACE) {
  648.             Object[] args = { new Boolean(readOnly) };
  649.             Debug.methodCall(this, "setReadOnly", args);
  650.             Debug.returnValue(this, "setReadOnly", new Boolean(readOnly));
  651.         }
  652.         checkClosed();
  653.         this.readOnly = readOnly;
  654.     }
  655.     /**
  656.      * Tests to see if the connection is in Read Only Mode.  Note that we
  657.      * cannot really put the database in read only mode, but we pretend we can
  658.      * by returning the value of the readOnly flag
  659.      *
  660.      * @return true if the connection is read only
  661.      *
  662.      * @exception java.sql.SQLException if a database access error occurs
  663.      */
  664.     public boolean isReadOnly() throws java.sql.SQLException {
  665.         if (Driver.TRACE) {
  666.             Object[] args = new Object[0];
  667.             Debug.methodCall(this, "isReadOnly", args);
  668.             Debug.returnValue(this, "isReadOnly", new Boolean(this.readOnly));
  669.         }
  670.         return this.readOnly;
  671.     }
  672.     /**
  673.      * @see Connection#setSavepoint()
  674.      */
  675.     public java.sql.Savepoint setSavepoint() throws SQLException {
  676.         throw new NotImplemented();
  677.     }
  678.     /**
  679.      * @see Connection#setSavepoint(String)
  680.      */
  681.     public java.sql.Savepoint setSavepoint(String arg0)
  682.         throws SQLException {
  683.         throw new NotImplemented();
  684.     }
  685.     /**
  686.      * DOCUMENT ME!
  687.      *
  688.      * @return DOCUMENT ME!
  689.      */
  690.     public TimeZone getServerTimezone() {
  691.         return this.serverTimezone;
  692.     }
  693.     /**
  694.      * DOCUMENT ME!
  695.      *
  696.      * @param level DOCUMENT ME!
  697.      *
  698.      * @throws java.sql.SQLException DOCUMENT ME!
  699.      * @throws SQLException DOCUMENT ME!
  700.      */
  701.     public void setTransactionIsolation(int level) throws java.sql.SQLException {
  702.         if (Driver.TRACE) {
  703.             Object[] args = { new Integer(level) };
  704.             Debug.methodCall(this, "setTransactionIsolation", args);
  705.         }
  706.         checkClosed();
  707.         if (this.hasIsolationLevels) {
  708.             StringBuffer sql = new StringBuffer(
  709.                     "SET SESSION TRANSACTION ISOLATION LEVEL ");
  710.             switch (level) {
  711.             case java.sql.Connection.TRANSACTION_NONE:
  712.                 throw new SQLException("Transaction isolation level "
  713.                     + "NONE not supported by MySQL");
  714.             case java.sql.Connection.TRANSACTION_READ_COMMITTED:
  715.                 sql.append("READ COMMITTED");
  716.                 break;
  717.             case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:
  718.                 sql.append("READ UNCOMMITTED");
  719.                 break;
  720.             case java.sql.Connection.TRANSACTION_REPEATABLE_READ:
  721.                 sql.append("REPEATABLE READ");
  722.                 break;
  723.             case java.sql.Connection.TRANSACTION_SERIALIZABLE:
  724.                 sql.append("SERIALIZABLE");
  725.                 break;
  726.             default:
  727.                 throw new SQLException("Unsupported transaction "
  728.                     + "isolation level '" + level + "'", "S1C00");
  729.             }
  730.             execSQL(sql.toString(), -1, this.database);
  731.             isolationLevel = level;
  732.         } else {
  733.             throw new java.sql.SQLException("Transaction Isolation Levels are "
  734.                 + "not supported on MySQL versions older than 3.23.36.", "S1C00");
  735.         }
  736.     }
  737.     /**
  738.      * Get this Connection's current transaction isolation mode.
  739.      *
  740.      * @return the current TRANSACTION_ mode value
  741.      *
  742.      * @exception java.sql.SQLException if a database access error occurs
  743.      * @throws SQLException DOCUMENT ME!
  744.      */
  745.     public int getTransactionIsolation() throws java.sql.SQLException {
  746.         if (Driver.TRACE) {
  747.             Object[] args = new Object[0];
  748.             Debug.methodCall(this, "getTransactionIsolation", args);
  749.             Debug.returnValue(this, "getTransactionIsolation",
  750.                 new Integer(isolationLevel));
  751.         }
  752.         if (this.hasIsolationLevels) {
  753.             java.sql.Statement stmt = null;
  754.             java.sql.ResultSet rs = null;
  755.             try {
  756.                 stmt = this.createStatement();
  757.                 if (stmt.getMaxRows() != 0) {
  758.                     stmt.setMaxRows(0);
  759.                 }
  760.                 String query = null;
  761.                 if (this.io.versionMeetsMinimum(4, 0, 3)) {
  762.                     query = "SHOW VARIABLES LIKE 'tx_isolation'";
  763.                 } else {
  764.                     query = "SHOW VARIABLES LIKE 'transaction_isolation'";
  765.                 }
  766.                 rs = stmt.executeQuery(query);
  767.                 if (rs.next()) {
  768.                     String s = rs.getString(2);
  769.                     if (s != null) {
  770.                         Integer intTI = (Integer) mapTransIsolationName2Value
  771.                             .get(s);
  772.                         if (intTI != null) {
  773.                             return intTI.intValue();
  774.                         }
  775.                     }
  776.                     throw new SQLException(
  777.                         "Could not map transaction isolation '" + s
  778.                         + " to a valid JDBC level.",
  779.                         SQLError.SQL_STATE_GENERAL_ERROR);
  780.                 } else {
  781.                     throw new SQLException("Could not retrieve transaction isolation level from server",
  782.                         SQLError.SQL_STATE_GENERAL_ERROR);
  783.                 }
  784.             } finally {
  785.                 if (rs != null) {
  786.                     try {
  787.                         rs.close();
  788.                     } catch (Exception ex) {
  789.                         // ignore
  790.                     }
  791.                     rs = null;
  792.                 }
  793.                 if (stmt != null) {
  794.                     try {
  795.                         stmt.close();
  796.                     } catch (Exception ex) {
  797.                         // ignore
  798.                     }
  799.                     stmt = null;
  800.                 }
  801.             }
  802.         }
  803.         return isolationLevel;
  804.     }
  805.     /**
  806.      * JDBC 2.0 Install a type-map object as the default type-map for this
  807.      * connection
  808.      *
  809.      * @param map the type mapping
  810.      *
  811.      * @throws SQLException if a database error occurs.
  812.      */
  813.     public void setTypeMap(java.util.Map map) throws SQLException {
  814.         this.typeMap = map;
  815.     }
  816.     /**
  817.      * JDBC 2.0 Get the type-map object associated with this connection. By
  818.      * default, the map returned is empty.
  819.      *
  820.      * @return the type map
  821.      *
  822.      * @throws SQLException if a database error occurs
  823.      */
  824.     public synchronized java.util.Map getTypeMap() throws SQLException {
  825.         if (this.typeMap == null) {
  826.             this.typeMap = new HashMap();
  827.         }
  828.         return this.typeMap;
  829.     }
  830.     /**
  831.      * The first warning reported by calls on this Connection is returned.
  832.      * <B>Note:</B> Sebsequent warnings will be changed to this
  833.      * java.sql.SQLWarning
  834.      *
  835.      * @return the first java.sql.SQLWarning or null
  836.      *
  837.      * @exception java.sql.SQLException if a database access error occurs
  838.      */
  839.     public java.sql.SQLWarning getWarnings() throws java.sql.SQLException {
  840.         if (Driver.TRACE) {
  841.             Object[] args = new Object[0];
  842.             Debug.methodCall(this, "getWarnings", args);
  843.             Debug.returnValue(this, "getWarnings", null);
  844.         }
  845.         return null;
  846.     }
  847.     /**
  848.      * Allow use of LOAD LOCAL INFILE?
  849.      *
  850.      * @return true if allowLoadLocalInfile was set to true.
  851.      */
  852.     public boolean allowLoadLocalInfile() {
  853.         return this.allowLoadLocalInfile;
  854.     }
  855.     /**
  856.      * DOCUMENT ME!
  857.      *
  858.      * @return DOCUMENT ME!
  859.      */
  860.     public boolean capitalizeDBMDTypes() {
  861.         return this.capitalizeDBMDTypes;
  862.     }
  863.     /**
  864.      * After this call, getWarnings returns null until a new warning is
  865.      * reported for this connection.
  866.      *
  867.      * @exception java.sql.SQLException if a database access error occurs
  868.      */
  869.     public void clearWarnings() throws java.sql.SQLException {
  870.         if (Driver.TRACE) {
  871.             Object[] args = new Object[0];
  872.             Debug.methodCall(this, "clearWarnings", args);
  873.         }
  874.         // firstWarning = null;
  875.     }
  876.     /**
  877.      * In some cases, it is desirable to immediately release a Connection's
  878.      * database and JDBC resources instead of waiting for them to be
  879.      * automatically released (cant think why off the top of my head)
  880.      * <B>Note:</B> A Connection is automatically closed when it is garbage
  881.      * collected.  Certain fatal errors also result in a closed connection.
  882.      *
  883.      * @exception java.sql.SQLException if a database access error occurs
  884.      */
  885.     public void close() throws java.sql.SQLException {
  886.         if (this.explicitCloseLocation == null) {
  887.             this.explicitCloseLocation = new Throwable();
  888.         }
  889.         realClose(true, true);
  890.     }
  891.     /**
  892.      * The method commit() makes all changes made since the previous
  893.      * commit/rollback permanent and releases any database locks currently
  894.      * held by the Connection.  This method should only be used when
  895.      * auto-commit has been disabled.
  896.      * 
  897.      * <p>
  898.      * <b>Note:</b> MySQL does not support transactions, so this method is a
  899.      * no-op.
  900.      * </p>
  901.      *
  902.      * @exception java.sql.SQLException if a database access error occurs
  903.      * @throws SQLException DOCUMENT ME!
  904.      *
  905.      * @see setAutoCommit
  906.      */
  907.     public void commit() throws java.sql.SQLException {
  908.         if (Driver.TRACE) {
  909.             Object[] args = new Object[0];
  910.             Debug.methodCall(this, "commit", args);
  911.         }
  912.         checkClosed();
  913.         try {
  914.             // no-op if _relaxAutoCommit == true
  915.             if (this.autoCommit && !this.relaxAutoCommit) {
  916.                 throw new SQLException("Can't call commit when autocommit=true",
  917.                     SQLError.SQL_STATE_GENERAL_ERROR);
  918.             } else if (this.transactionsSupported) {
  919.                 execSQL("commit", -1, this.database);
  920.             }
  921.         } finally {
  922.             if (this.reconnectAtTxEnd) {
  923.                 pingAndReconnect(true);
  924.             }
  925.         }
  926.         return;
  927.     }
  928.     //--------------------------JDBC 2.0-----------------------------
  929.     /**
  930.      * JDBC 2.0 Same as createStatement() above, but allows the default result
  931.      * set type and result set concurrency type to be overridden.
  932.      *
  933.      * @param resultSetType a result set type, see ResultSet.TYPE_XXX
  934.      * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
  935.      *
  936.      * @return a new Statement object
  937.      *
  938.      * @exception SQLException if a database-access error occurs.
  939.      */
  940.     public java.sql.Statement createStatement(int resultSetType,
  941.         int resultSetConcurrency) throws SQLException {
  942.         checkClosed();
  943.         Statement stmt = new com.mysql.jdbc.Statement(this, this.database);
  944.         stmt.setResultSetType(resultSetType);
  945.         stmt.setResultSetConcurrency(resultSetConcurrency);
  946.         return stmt;
  947.     }
  948.     /**
  949.      * SQL statements without parameters are normally executed using Statement
  950.      * objects.  If the same SQL statement is executed many times, it is more
  951.      * efficient to use a PreparedStatement
  952.      *
  953.      * @return a new Statement object
  954.      *
  955.      * @throws SQLException passed through from the constructor
  956.      */
  957.     public java.sql.Statement createStatement() throws SQLException {
  958.         return createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
  959.             java.sql.ResultSet.CONCUR_READ_ONLY);
  960.     }
  961.     /**
  962.      * @see Connection#createStatement(int, int, int)
  963.      */
  964.     public java.sql.Statement createStatement(int resultSetType,
  965.         int resultSetConcurrency, int resultSetHoldability)
  966.         throws SQLException {
  967.         if (this.pedantic) {
  968.             if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
  969.                 throw new SQLException("HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
  970.                     SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
  971.             }
  972.         }
  973.         return createStatement(resultSetType, resultSetConcurrency);
  974.     }
  975.     /**
  976.      * DOCUMENT ME!
  977.      *
  978.      * @throws Throwable DOCUMENT ME!
  979.      */
  980.     public void finalize() throws Throwable {
  981.         cleanup(null);
  982.     }
  983.     /**
  984.      * Is the server configured to use lower-case table names only?
  985.      *
  986.      * @return true if lower_case_table_names is 'on'
  987.      */
  988.     public boolean lowerCaseTableNames() {
  989.         return this.lowerCaseTableNames;
  990.     }
  991.     /**
  992.      * A driver may convert the JDBC sql grammar into its system's native SQL
  993.      * grammar prior to sending it; nativeSQL returns the native form of the
  994.      * statement that the driver would have sent.
  995.      *
  996.      * @param sql a SQL statement that may contain one or more '?' parameter
  997.      *        placeholders
  998.      *
  999.      * @return the native form of this statement
  1000.      *
  1001.      * @exception java.sql.SQLException if a database access error occurs
  1002.      */
  1003.     public String nativeSQL(String sql) throws java.sql.SQLException {
  1004.         if (Driver.TRACE) {
  1005.             Object[] args = { sql };
  1006.             Debug.methodCall(this, "nativeSQL", args);
  1007.             Debug.returnValue(this, "nativeSQL", sql);
  1008.         }
  1009.         return EscapeProcessor.escapeSQL(sql,
  1010.             getIO().versionMeetsMinimum(4, 0, 2));
  1011.     }
  1012.     /**
  1013.      * DOCUMENT ME!
  1014.      *
  1015.      * @param sql DOCUMENT ME!
  1016.      *
  1017.      * @return DOCUMENT ME!
  1018.      *
  1019.      * @throws java.sql.SQLException DOCUMENT ME!
  1020.      */
  1021.     public java.sql.CallableStatement prepareCall(String sql)
  1022.         throws java.sql.SQLException {
  1023.         if (this.getUseUltraDevWorkAround()) {
  1024.             return new UltraDevWorkAround(prepareStatement(sql));
  1025.         } else {
  1026.             throw new java.sql.SQLException("Callable statments not "
  1027.                 + "supported.", "S1C00");
  1028.         }
  1029.     }
  1030.     /**
  1031.      * JDBC 2.0 Same as prepareCall() above, but allows the default result set
  1032.      * type and result set concurrency type to be overridden.
  1033.      *
  1034.      * @param sql the SQL representing the callable statement
  1035.      * @param resultSetType a result set type, see ResultSet.TYPE_XXX
  1036.      * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
  1037.      *
  1038.      * @return a new CallableStatement object containing the pre-compiled SQL
  1039.      *         statement
  1040.      *
  1041.      * @exception SQLException if a database-access error occurs.
  1042.      */
  1043.     public java.sql.CallableStatement prepareCall(String sql,
  1044.         int resultSetType, int resultSetConcurrency) throws SQLException {
  1045.         return prepareCall(sql);
  1046.     }
  1047.     /**
  1048.      * @see Connection#prepareCall(String, int, int, int)
  1049.      */
  1050.     public java.sql.CallableStatement prepareCall(String sql,
  1051.         int resultSetType, int resultSetConcurrency, int resultSetHoldability)
  1052.         throws SQLException {
  1053.         if (this.pedantic) {
  1054.             if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
  1055.                 throw new SQLException("HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
  1056.                     SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
  1057.             }
  1058.         }
  1059.         throw new NotImplemented();
  1060.     }
  1061.     /**
  1062.      * A SQL statement with or without IN parameters can be pre-compiled and
  1063.      * stored in a PreparedStatement object.  This object can then be used to
  1064.      * efficiently execute this statement multiple times.
  1065.      * 
  1066.      * <p>
  1067.      * <B>Note:</B> This method is optimized for handling parametric SQL
  1068.      * statements that benefit from precompilation if the driver supports
  1069.      * precompilation. In this case, the statement is not sent to the database
  1070.      * until the PreparedStatement is executed.  This has no direct effect on
  1071.      * users; however it does affect which method throws certain
  1072.      * java.sql.SQLExceptions
  1073.      * </p>
  1074.      * 
  1075.      * <p>
  1076.      * MySQL does not support precompilation of statements, so they are handled
  1077.      * by the driver.
  1078.      * </p>
  1079.      *
  1080.      * @param sql a SQL statement that may contain one or more '?' IN parameter
  1081.      *        placeholders
  1082.      *
  1083.      * @return a new PreparedStatement object containing the pre-compiled
  1084.      *         statement.
  1085.      *
  1086.      * @exception java.sql.SQLException if a database access error occurs.
  1087.      */
  1088.     public java.sql.PreparedStatement prepareStatement(String sql)
  1089.         throws java.sql.SQLException {
  1090.         return prepareStatement(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY,
  1091.             java.sql.ResultSet.CONCUR_READ_ONLY);
  1092.     }
  1093.     /**
  1094.      * JDBC 2.0 Same as prepareStatement() above, but allows the default result
  1095.      * set type and result set concurrency type to be overridden.
  1096.      *
  1097.      * @param sql the SQL query containing place holders
  1098.      * @param resultSetType a result set type, see ResultSet.TYPE_XXX
  1099.      * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
  1100.      *
  1101.      * @return a new PreparedStatement object containing the pre-compiled SQL
  1102.      *         statement
  1103.      *
  1104.      * @exception SQLException if a database-access error occurs.
  1105.      */
  1106.     public synchronized java.sql.PreparedStatement prepareStatement(
  1107.         String sql, int resultSetType, int resultSetConcurrency)
  1108.         throws SQLException {
  1109.         checkClosed();
  1110.         PreparedStatement pStmt = null;
  1111.         if (this.cachePreparedStatements) {
  1112.             PreparedStatement.ParseInfo pStmtInfo = (PreparedStatement.ParseInfo) cachedPreparedStatementParams
  1113.                 .get(sql);
  1114.             if (pStmtInfo == null) {
  1115.                 pStmt = new com.mysql.jdbc.PreparedStatement(this, sql,
  1116.                         this.database);
  1117.                 PreparedStatement.ParseInfo parseInfo = pStmt.getParseInfo();
  1118.                 if (parseInfo.statementLength < this.preparedStatementCacheMaxSqlSize) {
  1119.                     if (this.cachedPreparedStatementParams.size() >= 25) {
  1120.                         Iterator oldestIter = this.cachedPreparedStatementParams.keySet()
  1121.                                                                                 .iterator();
  1122.                         long lruTime = Long.MAX_VALUE;
  1123.                         String oldestSql = null;
  1124.                         while (oldestIter.hasNext()) {
  1125.                             String sqlKey = (String) oldestIter.next();
  1126.                             PreparedStatement.ParseInfo lruInfo = (PreparedStatement.ParseInfo) this.cachedPreparedStatementParams
  1127.                                 .get(sqlKey);
  1128.                             if (lruInfo.lastUsed < lruTime) {
  1129.                                 lruTime = lruInfo.lastUsed;
  1130.                                 oldestSql = sqlKey;
  1131.                             }
  1132.                         }
  1133.                         if (oldestSql != null) {
  1134.                             this.cachedPreparedStatementParams.remove(oldestSql);
  1135.                         }
  1136.                     }
  1137.                     cachedPreparedStatementParams.put(sql, pStmt.getParseInfo());
  1138.                 }
  1139.             } else {
  1140.                 pStmtInfo.lastUsed = System.currentTimeMillis();
  1141.                 pStmt = new com.mysql.jdbc.PreparedStatement(this, sql,
  1142.                         this.database, pStmtInfo);
  1143.             }
  1144.         } else {
  1145.             pStmt = new com.mysql.jdbc.PreparedStatement(this, sql,
  1146.                     this.database);
  1147.         }
  1148.         //
  1149.         // FIXME: Create warnings if can't create results of the given
  1150.         //        type or concurrency
  1151.         //
  1152.         pStmt.setResultSetType(resultSetType);
  1153.         pStmt.setResultSetConcurrency(resultSetConcurrency);
  1154.         return pStmt;
  1155.     }
  1156.     /**
  1157.      * @see Connection#prepareStatement(String, int, int, int)
  1158.      */
  1159.     public java.sql.PreparedStatement prepareStatement(String sql,
  1160.         int resultSetType, int resultSetConcurrency, int resultSetHoldability)
  1161.         throws SQLException {
  1162.         if (this.pedantic) {
  1163.             if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
  1164.                 throw new SQLException("HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
  1165.                     SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
  1166.             }
  1167.         }
  1168.         return prepareStatement(sql, resultSetType, resultSetConcurrency);
  1169.     }
  1170.     /**
  1171.      * @see Connection#prepareStatement(String, int)
  1172.      */
  1173.     public java.sql.PreparedStatement prepareStatement(String sql,
  1174.         int autoGenKeyIndex) throws SQLException {
  1175.         java.sql.PreparedStatement pStmt = prepareStatement(sql);
  1176.         ((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys(autoGenKeyIndex == Statement.RETURN_GENERATED_KEYS);
  1177.         return pStmt;
  1178.     }
  1179.     /**
  1180.      * @see Connection#prepareStatement(String, int[])
  1181.      */
  1182.     public java.sql.PreparedStatement prepareStatement(String sql,
  1183.         int[] autoGenKeyIndexes) throws SQLException {
  1184.         java.sql.PreparedStatement pStmt = prepareStatement(sql);
  1185.         ((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys((autoGenKeyIndexes != null)
  1186.             && (autoGenKeyIndexes.length > 0));
  1187.         return pStmt;
  1188.     }
  1189.     /**
  1190.      * @see Connection#prepareStatement(String, String[])
  1191.      */
  1192.     public java.sql.PreparedStatement prepareStatement(String sql,
  1193.         String[] autoGenKeyColNames) throws SQLException {
  1194.         java.sql.PreparedStatement pStmt = prepareStatement(sql);
  1195.         ((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys((autoGenKeyColNames != null)
  1196.             && (autoGenKeyColNames.length > 0));
  1197.         return pStmt;
  1198.     }
  1199.     /**
  1200.      * @see Connection#releaseSavepoint(Savepoint)
  1201.      */
  1202.     public void releaseSavepoint(Savepoint arg0) throws SQLException {
  1203.         throw new NotImplemented();
  1204.     }
  1205.     /**
  1206.      * The method rollback() drops all changes made since the previous
  1207.      * commit/rollback and releases any database locks currently held by the
  1208.      * Connection.
  1209.      *
  1210.      * @exception java.sql.SQLException if a database access error occurs
  1211.      * @throws SQLException DOCUMENT ME!
  1212.      *
  1213.      * @see commit
  1214.      */
  1215.     public void rollback() throws java.sql.SQLException {
  1216.         if (Driver.TRACE) {
  1217.             Object[] args = new Object[0];
  1218.             Debug.methodCall(this, "rollback", args);
  1219.         }
  1220.         checkClosed();
  1221.         try {
  1222.             // no-op if _relaxAutoCommit == true
  1223.             if (this.autoCommit && !this.relaxAutoCommit) {
  1224.                 throw new SQLException("Can't call rollback when autocommit=true",
  1225.                     SQLError.SQL_STATE_GENERAL_ERROR);
  1226.             } else if (this.transactionsSupported) {
  1227.                 try {
  1228.                     rollbackNoChecks();
  1229.                 } catch (SQLException sqlEx) {
  1230.                     // We ignore non-transactional tables if told to do so
  1231.                     if (this.ignoreNonTxTables
  1232.                             && (sqlEx.getErrorCode() != MysqlDefs.ER_WARNING_NOT_COMPLETE_ROLLBACK)) {
  1233.                         throw sqlEx;
  1234.                     }
  1235.                 }
  1236.             }
  1237.         } finally {
  1238.             if (this.reconnectAtTxEnd) {
  1239.                 pingAndReconnect(true);
  1240.             }
  1241.         }
  1242.     }
  1243.     /**
  1244.      * @see Connection#rollback(Savepoint)
  1245.      */
  1246.     public void rollback(Savepoint arg0) throws SQLException {
  1247.         throw new NotImplemented();
  1248.     }
  1249.     /**
  1250.      * Used by MiniAdmin to shutdown a MySQL server
  1251.      *
  1252.      * @throws SQLException if the command can not be issued.
  1253.      */
  1254.     public void shutdownServer() throws SQLException {
  1255.         try {
  1256.             this.io.sendCommand(MysqlDefs.SHUTDOWN, null, null);
  1257.         } catch (Exception ex) {
  1258.             throw new SQLException("Unhandled exception '" + ex.toString()
  1259.                 + "'", SQLError.SQL_STATE_GENERAL_ERROR);
  1260.         }
  1261.     }
  1262.     /**
  1263.      * DOCUMENT ME!
  1264.      *
  1265.      * @return DOCUMENT ME!
  1266.      */
  1267.     public boolean supportsIsolationLevel() {
  1268.         return this.hasIsolationLevels;
  1269.     }
  1270.     /**
  1271.      * DOCUMENT ME!
  1272.      *
  1273.      * @return DOCUMENT ME!
  1274.      */
  1275.     public boolean supportsQuotedIdentifiers() {
  1276.         return this.hasQuotedIdentifiers;
  1277.     }
  1278.     /**
  1279.      * DOCUMENT ME!
  1280.      *
  1281.      * @return DOCUMENT ME!
  1282.      */
  1283.     public boolean supportsTransactions() {
  1284.         return this.transactionsSupported;
  1285.     }
  1286.     /**
  1287.      * Should we use compression?
  1288.      *
  1289.      * @return should we use compression to communicate with the server?
  1290.      */
  1291.     public boolean useCompression() {
  1292.         return this.useCompression;
  1293.     }
  1294.     /**
  1295.      * Returns the paranoidErrorMessages.
  1296.      *
  1297.      * @return boolean if we should be paranoid about error messages.
  1298.      */
  1299.     public boolean useParanoidErrorMessages() {
  1300.         return paranoid;
  1301.     }
  1302.     /**
  1303.      * Should we use SSL?
  1304.      *
  1305.      * @return should we use SSL to communicate with the server?
  1306.      */
  1307.     public boolean useSSL() {
  1308.         return this.useSSL;
  1309.     }
  1310.     /**
  1311.      * Should we enable work-arounds for floating point rounding errors in the
  1312.      * server?
  1313.      *
  1314.      * @return should we use floating point work-arounds?
  1315.      */
  1316.     public boolean useStrictFloatingPoint() {
  1317.         return this.strictFloatingPoint;
  1318.     }
  1319.     /**
  1320.      * Returns the strictUpdates value.
  1321.      *
  1322.      * @return boolean
  1323.      */
  1324.     public boolean useStrictUpdates() {
  1325.         return strictUpdates;
  1326.     }
  1327.     /**
  1328.      * DOCUMENT ME!
  1329.      *
  1330.      * @return DOCUMENT ME!
  1331.      */
  1332.     public boolean useTimezone() {
  1333.         return this.useTimezone;
  1334.     }
  1335.     /**
  1336.      * Should unicode character mapping be used ?
  1337.      *
  1338.      * @return should we use Unicode character mapping?
  1339.      */
  1340.     public boolean useUnicode() {
  1341.         return this.doUnicode;
  1342.     }
  1343.     /**
  1344.      * DOCUMENT ME!
  1345.      *
  1346.      * @return Returns the defaultTimeZone.
  1347.      */
  1348.     protected TimeZone getDefaultTimeZone() {
  1349.         return defaultTimeZone;
  1350.     }
  1351.     /**
  1352.      * Returns the IO channel to the server
  1353.      *
  1354.      * @return the IO channel to the server
  1355.      *
  1356.      * @throws SQLException if the connection is closed.
  1357.      */
  1358.     protected MysqlIO getIO() throws SQLException {
  1359.         if ((this.io == null) || this.isClosed) {
  1360.             throw new SQLException("Operation not allowed on closed connection",
  1361.                 "08003");
  1362.         }
  1363.         return this.io;
  1364.     }
  1365.     protected int getNetWriteTimeout() {
  1366.         String netWriteTimeoutStr = (String) this.serverVariables.get(
  1367.                 "net_write_timeout");
  1368.         if (netWriteTimeoutStr != null) {
  1369.             try {
  1370.                 return Integer.parseInt(netWriteTimeoutStr);
  1371.             } catch (NumberFormatException nfe) {
  1372.                 return Integer.MAX_VALUE;
  1373.             }
  1374.         } else {
  1375.             return Integer.MAX_VALUE;
  1376.         }
  1377.     }
  1378.     /**
  1379.      * Is this connection using unbuffered input?
  1380.      *
  1381.      * @return whether or not to use buffered input streams
  1382.      */
  1383.     protected boolean isUsingUnbufferedInput() {
  1384.         return this.useUnbufferedInput;
  1385.     }
  1386.     /**
  1387.      * Creates an IO channel to the server
  1388.      *
  1389.      * @param isForReconnect is this request for a re-connect
  1390.      *
  1391.      * @return a new MysqlIO instance connected to a server
  1392.      *
  1393.      * @throws SQLException if a database access error occurs
  1394.      */
  1395.     protected com.mysql.jdbc.MysqlIO createNewIO(boolean isForReconnect)
  1396.         throws SQLException {
  1397.         MysqlIO newIo = null;
  1398.         if (!highAvailability && !this.failedOver) {
  1399.             for (int hostIndex = 0; hostIndex < hostListSize; hostIndex++) {
  1400.                 try {
  1401.                     this.io = new MysqlIO(this.hostList.get(hostIndex).toString(),
  1402.                             this.port, this.socketFactoryClassName, this.props,
  1403.                             this, this.socketTimeout);
  1404.                     this.io.doHandshake(this.user, this.password, this.database);
  1405.                     this.isClosed = false;
  1406.                     if (this.database.length() != 0) {
  1407.                         this.io.sendCommand(MysqlDefs.INIT_DB, this.database,
  1408.                             null);
  1409.                     }
  1410.                     // save state from old connection
  1411.                     boolean autoCommit = getAutoCommit();
  1412.                     int oldIsolationLevel = getTransactionIsolation();
  1413.                     boolean oldReadOnly = isReadOnly();
  1414.                     String oldCatalog = getCatalog();
  1415.                     // Server properties might be different
  1416.                     // from previous connection, so initialize
  1417.                     // again...
  1418.                     initializePropsFromServer(this.props);
  1419.                     if (isForReconnect) {
  1420.                         // Restore state from old connection
  1421.                         setAutoCommit(autoCommit);
  1422.                         if (this.hasIsolationLevels) {
  1423.                             setTransactionIsolation(oldIsolationLevel);
  1424.                         }
  1425.                         setCatalog(oldCatalog);
  1426.                     }
  1427.                     if (hostIndex != 0) {
  1428.                         setFailedOverState();
  1429.                     } else {
  1430.                         this.failedOver = false;
  1431.                         if (hostListSize > 1) {
  1432.                             setReadOnly(false);
  1433.                         } else {
  1434.                             setReadOnly(oldReadOnly);
  1435.                         }
  1436.                     }
  1437.                     break; // low-level connection succeeded
  1438.                 } catch (SQLException sqlEx) {
  1439.                     if (this.io != null) {
  1440.                         this.io.forceClose();
  1441.                     }
  1442.                     String sqlState = sqlEx.getSQLState();
  1443.                     if ((sqlState == null)
  1444.                             || !sqlState.equals(
  1445.                                 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)) {
  1446.                         throw sqlEx;
  1447.                     }
  1448.                     if ((hostListSize - 1) == hostIndex) {
  1449.                         throw sqlEx;
  1450.                     }
  1451.                 } catch (Exception unknownException) {
  1452.                     if (this.io != null) {
  1453.                         this.io.forceClose();
  1454.                     }
  1455.                     if ((hostListSize - 1) == hostIndex) {
  1456.                         throw new SQLException(
  1457.                             "Unable to connect to any hosts due to exception: "
  1458.                             + unknownException.toString(),
  1459.                             SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE);
  1460.                     }
  1461.                 }
  1462.             }
  1463.         } else {
  1464.             double timeout = this.initialTimeout;
  1465.             boolean connectionGood = false;
  1466.             Exception connectionException = null;
  1467.             for (int hostIndex = 0;
  1468.                     (hostIndex < hostListSize) && !connectionGood;
  1469.                     hostIndex++) {
  1470.                 for (int attemptCount = 0;
  1471.                         !connectionGood && (attemptCount < this.maxReconnects);
  1472.                         attemptCount++) {
  1473.                     try {
  1474.                         if (this.io != null) {
  1475.                             this.io.forceClose();
  1476.                         }
  1477.                         this.io = new MysqlIO(this.hostList.get(hostIndex)
  1478.                                                            .toString(),
  1479.                                 this.port, this.socketFactoryClassName,
  1480.                                 this.props, this, this.socketTimeout);
  1481.                         this.io.doHandshake(this.user, this.password,
  1482.                             this.database);
  1483.                         if (this.database.length() != 0) {
  1484.                             this.io.sendCommand(MysqlDefs.INIT_DB,
  1485.                                 this.database, null);
  1486.                         }
  1487.                         ping();
  1488.                         this.isClosed = false;
  1489.                         // save state from old connection
  1490.                         boolean autoCommit = getAutoCommit();
  1491.                         int oldIsolationLevel = getTransactionIsolation();
  1492.                         boolean oldReadOnly = isReadOnly();
  1493.                         String oldCatalog = getCatalog();
  1494.                         // Server properties might be different
  1495.                         // from previous connection, so initialize
  1496.                         // again...
  1497.                         initializePropsFromServer(this.props);
  1498.                         if (isForReconnect) {
  1499.                             // Restore state from old connection
  1500.                             setAutoCommit(autoCommit);
  1501.                             if (this.hasIsolationLevels) {
  1502.                                 setTransactionIsolation(oldIsolationLevel);
  1503.                             }
  1504.                             setCatalog(oldCatalog);
  1505.                         }
  1506.                         connectionGood = true;
  1507.                         if (hostIndex != 0) {
  1508.                             setFailedOverState();
  1509.                         } else {
  1510.                             this.failedOver = false;
  1511.                             if (hostListSize > 1) {
  1512.                                 setReadOnly(false);
  1513.                             } else {
  1514.                                 setReadOnly(oldReadOnly);
  1515.                             }
  1516.                         }
  1517.                         break;
  1518.                     } catch (Exception EEE) {
  1519.                         connectionException = EEE;
  1520.                         connectionGood = false;
  1521.                     }
  1522.                     if (!connectionGood) {
  1523.                         try {
  1524.                             Thread.sleep((long) timeout * 1000);
  1525.                             timeout = timeout * 2;
  1526.                         } catch (InterruptedException IE) {
  1527.                             ;
  1528.                         }
  1529.                     }
  1530.                 }
  1531.                 if (!connectionGood) {
  1532.                     // We've really failed!
  1533.                     throw new SQLException(
  1534.                         "Server connection failure during transaction. Due to underlying exception: '"
  1535.                         + connectionException + "'.nAttempted reconnect "
  1536.                         + this.maxReconnects + " times. Giving up.",
  1537.                         SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
  1538.                 }
  1539.             }
  1540.         }
  1541.         if (paranoid && !highAvailability && (hostListSize <= 1)) {
  1542.             password = null;
  1543.             user = null;
  1544.         }
  1545.         return newIo;
  1546.     }
  1547.     /**
  1548.      * Closes connection and frees resources.
  1549.      *
  1550.      * @param calledExplicitly is this being called from close()
  1551.      * @param issueRollback should a rollback() be issued?
  1552.      *
  1553.      * @throws SQLException if an error occurs
  1554.      */
  1555.     protected void realClose(boolean calledExplicitly, boolean issueRollback)
  1556.         throws SQLException {
  1557.         if (Driver.TRACE) {
  1558.             Object[] args = new Object[] {
  1559.                     new Boolean(calledExplicitly), new Boolean(issueRollback)
  1560.                 };
  1561.             Debug.methodCall(this, "realClose", args);
  1562.         }
  1563.         SQLException sqlEx = null;
  1564.         if (!isClosed() && !getAutoCommit() && issueRollback) {
  1565.             try {
  1566.                 rollback();
  1567.             } catch (SQLException ex) {
  1568.                 sqlEx = ex;
  1569.             }
  1570.         }
  1571.         if (this.io != null) {
  1572.             try {
  1573.                 this.io.quit();
  1574.             } catch (Exception e) {
  1575.                 ;
  1576.             }
  1577.             this.io = null;
  1578.         }
  1579.         if (this.cachedPreparedStatementParams != null) {
  1580.             this.cachedPreparedStatementParams.clear();
  1581.             this.cachedPreparedStatementParams = null;
  1582.         }
  1583.         this.isClosed = true;
  1584.         if (sqlEx != null) {
  1585.             throw sqlEx;
  1586.         }
  1587.     }
  1588.     /**
  1589.      * Returns the locally mapped instance of a charset converter (to avoid
  1590.      * overhead of static synchronization).
  1591.      *
  1592.      * @param javaEncodingName the encoding name to retrieve
  1593.      *
  1594.      * @return a character converter, or null if one couldn't be mapped.
  1595.      */
  1596.     synchronized SingleByteCharsetConverter getCharsetConverter(
  1597.         String javaEncodingName) {
  1598.         SingleByteCharsetConverter converter = (SingleByteCharsetConverter) this.charsetConverterMap
  1599.             .get(javaEncodingName);
  1600.         if (converter == CHARSET_CONVERTER_NOT_AVAILABLE_MARKER) {
  1601.             return null;
  1602.         }
  1603.         if (converter == null) {
  1604.             try {
  1605.                 converter = SingleByteCharsetConverter.getInstance(javaEncodingName);
  1606.                 if (converter == null) {
  1607.                     this.charsetConverterMap.put(javaEncodingName,
  1608.                         CHARSET_CONVERTER_NOT_AVAILABLE_MARKER);
  1609.                 }
  1610.                 this.charsetConverterMap.put(javaEncodingName, converter);
  1611.             } catch (UnsupportedEncodingException unsupEncEx) {
  1612.                 this.charsetConverterMap.put(javaEncodingName,
  1613.                     CHARSET_CONVERTER_NOT_AVAILABLE_MARKER);
  1614.                 converter = null;
  1615.             }
  1616.         }
  1617.         return converter;
  1618.     }
  1619.     /**
  1620.      * Returns the maximum packet size the MySQL server will accept
  1621.      *
  1622.      * @return DOCUMENT ME!
  1623.      */
  1624.     int getMaxAllowedPacket() {
  1625.         return this.maxAllowedPacket;
  1626.     }
  1627.     /**
  1628.      * DOCUMENT ME!
  1629.      *
  1630.      * @return the max rows to return for statements (by default)
  1631.      */
  1632.     int getMaxRows() {
  1633.         return this.maxRows;
  1634.     }
  1635.     /**
  1636.      * Returns the Mutex all queries are locked against
  1637.      *
  1638.      * @return DOCUMENT ME!
  1639.      *
  1640.      * @throws SQLException DOCUMENT ME!
  1641.      */
  1642.     Object getMutex() throws SQLException {
  1643.         if (this.io == null) {
  1644.             throw new SQLException("Connection.close() has already been called. Invalid operation in this state.",
  1645.                 "08003");
  1646.         }
  1647.         return this.mutex;
  1648.     }
  1649.     /**
  1650.      * Returns the packet buffer size the MySQL server reported upon connection