Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/mysql/jdbc/Connection.java


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