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 PreparedStatement.ParseInfo pStmtInfo = (PreparedStatement.ParseInfo) cachedPreparedStatementParams
1376 .get(sql);
1377
1378 if (pStmtInfo == null) {
1379 pStmt = new com.mysql.jdbc.PreparedStatement(this, sql,
1380 this.database);
1381
1382 PreparedStatement.ParseInfo parseInfo = pStmt.getParseInfo();
1383
1384 if (parseInfo.statementLength < this.preparedStatementCacheMaxSqlSize) {
1385 if (this.cachedPreparedStatementParams.size() >= 25) {
1386 Iterator oldestIter = this.cachedPreparedStatementParams.keySet()
1387 .iterator();
1388 long lruTime = Long.MAX_VALUE;
1389 String oldestSql = null;
1390
1391 while (oldestIter.hasNext()) {
1392 String sqlKey = (String) oldestIter.next();
1393 PreparedStatement.ParseInfo lruInfo = (PreparedStatement.ParseInfo) this.cachedPreparedStatementParams
1394 .get(sqlKey);
1395
1396 if (lruInfo.lastUsed < lruTime) {
1397 lruTime = lruInfo.lastUsed;
1398 oldestSql = sqlKey;
1399 }
1400 }
1401
1402 if (oldestSql != null) {
1403 this.cachedPreparedStatementParams.remove(oldestSql);
1404 }
1405 }
1406
1407 cachedPreparedStatementParams.put(sql, pStmt.getParseInfo());
1408 }
1409 } else {
1410 pStmtInfo.lastUsed = System.currentTimeMillis();
1411 pStmt = new com.mysql.jdbc.PreparedStatement(this, sql,
1412 this.database, pStmtInfo);
1413 }
1414 } else {
1415 pStmt = new com.mysql.jdbc.PreparedStatement(this, sql,
1416 this.database);
1417 }
1418
1419 //
1420 // FIXME: Create warnings if can't create results of the given
1421 // type or concurrency
1422 //
1423 pStmt.setResultSetType(resultSetType);
1424 pStmt.setResultSetConcurrency(resultSetConcurrency);
1425
1426 return pStmt;
1427 }
1428
1429 /**
1430 * @see Connection#prepareStatement(String, int, int, int)
1431 */
1432 public java.sql.PreparedStatement prepareStatement(String sql,
1433 int resultSetType, int resultSetConcurrency, int resultSetHoldability)
1434 throws SQLException {
1435 if (this.pedantic) {
1436 if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
1437 throw new SQLException("HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
1438 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1439 }
1440 }
1441
1442 return prepareStatement(sql, resultSetType, resultSetConcurrency);
1443 }
1444
1445 /**
1446 * @see Connection#prepareStatement(String, int)
1447 */
1448 public java.sql.PreparedStatement prepareStatement(String sql,
1449 int autoGenKeyIndex) throws SQLException {
1450 java.sql.PreparedStatement pStmt = prepareStatement(sql);
1451
1452 ((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys(autoGenKeyIndex == Statement.RETURN_GENERATED_KEYS);
1453
1454 return pStmt;
1455 }
1456
1457 /**
1458 * @see Connection#prepareStatement(String, int[])
1459 */
1460 public java.sql.PreparedStatement prepareStatement(String sql,
1461 int[] autoGenKeyIndexes) throws SQLException {
1462 java.sql.PreparedStatement pStmt = prepareStatement(sql);
1463
1464 ((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys((autoGenKeyIndexes != null)
1465 && (autoGenKeyIndexes.length > 0));
1466
1467 return pStmt;
1468 }
1469
1470 /**
1471 * @see Connection#prepareStatement(String, String[])
1472 */
1473 public java.sql.PreparedStatement prepareStatement(String sql,
1474 String[] autoGenKeyColNames) throws SQLException {
1475 java.sql.PreparedStatement pStmt = prepareStatement(sql);
1476
1477 ((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys((autoGenKeyColNames != null)
1478 && (autoGenKeyColNames.length > 0));
1479
1480 return pStmt;
1481 }
1482
1483 /**
1484 * @see Connection#releaseSavepoint(Savepoint)
1485 */
1486 public void releaseSavepoint(Savepoint arg0) throws SQLException {
1487 throw new NotImplemented();
1488 }
1489
1490 /**
1491 * Resets the server-side state of this connection. Doesn't work for MySQL
1492 * versions older than 4.0.6 or if isParanoid() is set (it will become a
1493 * no-op in these cases). Usually only used from connection pooling code.
1494 *
1495 * @throws SQLException if the operation fails while resetting server
1496 * state.
1497 */
1498 public void resetServerState() throws SQLException {
1499
1500 if (!this.paranoid
1501 && ((this.io != null) & this.io.versionMeetsMinimum(4, 0, 6))) {
1502 changeUser(this.user, this.password);
1503 }
1504 }
1505
1506 /**
1507 * The method rollback() drops all changes made since the previous
1508 * commit/rollback and releases any database locks currently held by the
1509 * Connection.
1510 *
1511 * @exception java.sql.SQLException if a database access error occurs
1512 * @throws SQLException DOCUMENT ME!
1513 *
1514 * @see commit
1515 */
1516 public void rollback() throws java.sql.SQLException {
1517 if (Driver.TRACE) {
1518 Object[] args = new Object[0];
1519 Debug.methodCall(this, "rollback", args);
1520 }
1521
1522 checkClosed();
1523
1524 try {
1525 // no-op if _relaxAutoCommit == true
1526 if (this.autoCommit && !this.relaxAutoCommit) {
1527 throw new SQLException("Can't call rollback when autocommit=true",
1528 SQLError.SQL_STATE_GENERAL_ERROR);
1529 } else if (this.transactionsSupported) {
1530 try {
1531 rollbackNoChecks();
1532 } catch (SQLException sqlEx) {
1533 // We ignore non-transactional tables if told to do so
1534 if (this.ignoreNonTxTables
1535 && (sqlEx.getErrorCode() != MysqlDefs.ER_WARNING_NOT_COMPLETE_ROLLBACK)) {
1536 throw sqlEx;
1537 }
1538 }
1539 }
1540 } finally {
1541 if (this.reconnectAtTxEnd) {
1542 pingAndReconnect(true);
1543 }
1544 }
1545 }
1546
1547 /**
1548 * @see Connection#rollback(Savepoint)
1549 */
1550 public void rollback(Savepoint arg0) throws SQLException {
1551 throw new NotImplemented();
1552 }
1553
1554 /**
1555 * Used by MiniAdmin to shutdown a MySQL server
1556 *
1557 * @throws SQLException if the command can not be issued.
1558 */
1559 public void shutdownServer() throws SQLException {
1560 try {
1561 this.io.sendCommand(MysqlDefs.SHUTDOWN, null, null);
1562 } catch (Exception ex) {
1563 throw new SQLException("Unhandled exception '" + ex.toString()
1564 + "'", SQLError.SQL_STATE_GENERAL_ERROR);
1565 }
1566 }
1567
1568 /**
1569 * DOCUMENT ME!
1570 *
1571 * @return DOCUMENT ME!
1572 */
1573 public boolean supportsIsolationLevel() {
1574 return this.hasIsolationLevels;
1575 }
1576
1577 /**
1578 * DOCUMENT ME!
1579 *
1580 * @return DOCUMENT ME!
1581 */
1582 public boolean supportsQuotedIdentifiers() {
1583 return this.hasQuotedIdentifiers;
1584 }
1585
1586 /**
1587 * DOCUMENT ME!
1588 *
1589 * @return DOCUMENT ME!
1590 */
1591 public boolean supportsTransactions() {
1592 return this.transactionsSupported;
1593 }
1594
1595 /**
1596 * Should we use compression?
1597 *
1598 * @return should we use compression to communicate with the server?
1599 */
1600 public boolean useCompression() {
1601 return this.useCompression;
1602 }
1603
1604 /**
1605 * Returns the paranoidErrorMessages.
1606 *
1607 * @return boolean if we should be paranoid about error messages.
1608 */
1609 public boolean useParanoidErrorMessages() {
1610 return paranoid;
1611 }
1612
1613 /**
1614 * Should we use SSL?
1615 *
1616 * @return should we use SSL to communicate with the server?
1617 */
1618 public boolean useSSL() {
1619 return this.useSSL;
1620 }
1621
1622 /**
1623 * Should we enable work-arounds for floating point rounding errors in the
1624 * server?
1625 *
1626 * @return should we use floating point work-arounds?
1627 */
1628 public boolean useStrictFloatingPoint() {
1629 return this.strictFloatingPoint;
1630 }
1631
1632 /**
1633 * Returns the strictUpdates value.
1634 *
1635 * @return boolean
1636 */
1637 public boolean useStrictUpdates() {
1638 return strictUpdates;
1639 }
1640
1641 /**
1642 * DOCUMENT ME!
1643 *
1644 * @return DOCUMENT ME!
1645 */
1646 public boolean useTimezone() {
1647 return this.useTimezone;
1648 }
1649
1650 /**
1651 * Should unicode character mapping be used ?
1652 *
1653 * @return should we use Unicode character mapping?
1654 */
1655 public boolean useUnicode() {
1656 return this.doUnicode;
1657 }
1658
1659 /**
1660 * Returns the Java character encoding name for the given MySQL server
1661 * charset index
1662 *
1663 * @param charsetIndex
1664 *
1665 * @return the Java character encoding name for the given MySQL server
1666 * charset index
1667 *
1668 * @throws SQLException if the character set index isn't known by the
1669 * driver
1670 */
1671 protected String getCharsetNameForIndex(int charsetIndex)
1672 throws SQLException {
1673 String charsetName = null;
1674
1675 if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) {
1676 try {
1677 charsetName = this.indexToCharsetMapping[charsetIndex];
1678 } catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
1679 throw new SQLException(
1680 "Unknown character set index for field '" + charsetIndex
1681 + "' received from server.",
1682 SQLError.SQL_STATE_GENERAL_ERROR);
1683 }
1684
1685 // Punt
1686 if (charsetName == null) {
1687 charsetName = getEncoding();
1688 }
1689 } else {
1690 charsetName = getEncoding();
1691 }
1692
1693 return charsetName;
1694 }
1695
1696 /**
1697 * DOCUMENT ME!
1698 *
1699 * @return Returns the defaultTimeZone.
1700 */
1701 protected TimeZone getDefaultTimeZone() {
1702 return defaultTimeZone;
1703 }
1704
1705 /**
1706 * Returns the IO channel to the server
1707 *
1708 * @return the IO channel to the server
1709 *
1710 * @throws SQLException if the connection is closed.
1711 */
1712 protected MysqlIO getIO() throws SQLException {
1713 if ((this.io == null) || this.isClosed) {
1714 throw new SQLException("Operation not allowed on closed connection",
1715 "08003");
1716 }
1717
1718 return this.io;
1719 }
1720
1721 protected int getNetWriteTimeout() {
1722 String netWriteTimeoutStr = (String) this.serverVariables.get(
1723 "net_write_timeout");
1724
1725 if (netWriteTimeoutStr != null) {
1726 try {
1727 return Integer.parseInt(netWriteTimeoutStr);
1728 } catch (NumberFormatException nfe) {
1729 return Integer.MAX_VALUE;
1730 }
1731 } else {
1732 return Integer.MAX_VALUE;
1733 }
1734 }
1735
1736 /**
1737 * Is this connection using unbuffered input?
1738 *
1739 * @return whether or not to use buffered input streams
1740 */
1741 protected boolean isUsingUnbufferedInput() {
1742 return this.useUnbufferedInput;
1743 }
1744
1745 /**
1746 * Creates an IO channel to the server
1747 *
1748 * @param isForReconnect is this request for a re-connect
1749 *
1750 * @return a new MysqlIO instance connected to a server
1751 *
1752 * @throws SQLException if a database access error occurs
1753 */
1754 protected com.mysql.jdbc.MysqlIO createNewIO(boolean isForReconnect)
1755 throws SQLException {
1756 MysqlIO newIo = null;
1757
1758 if (!highAvailability && !this.failedOver) {
1759 for (int hostIndex = 0; hostIndex < hostListSize; hostIndex++) {
1760 try {
1761 String newHostPortPair = (String) this.hostList.get(hostIndex);
1762
1763 int newPort = 3306;
1764
1765 String[] hostPortPair = NonRegisteringDriver.parseHostPortPair(newHostPortPair);
1766 String newHost = hostPortPair[NonRegisteringDriver.HOST_NAME_INDEX];
1767
1768 if (newHost == null || newHost.trim().length() == 0) {
1769 newHost = "localhost";
1770 }
1771
1772 if (hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] != null) {
1773 try {
1774 newPort = Integer.parseInt(hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]);
1775 } catch (NumberFormatException nfe) {
1776 throw new SQLException(
1777 "Illegal connection port value '"
1778 + hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] + "'",
1779 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
1780 }
1781 }
1782
1783 this.io = new MysqlIO(newHost, newPort,
1784 this.socketFactoryClassName, this.props, this,
1785 this.socketTimeout);
1786 this.io.doHandshake(this.user, this.password, this.database);
1787 this.isClosed = false;
1788
1789 if (this.database.length() != 0) {
1790 this.io.sendCommand(MysqlDefs.INIT_DB, this.database,
1791 null);
1792 }
1793
1794 // save state from old connection
1795 boolean autoCommit = getAutoCommit();
1796 int oldIsolationLevel = getTransactionIsolation();
1797 boolean oldReadOnly = isReadOnly();
1798 String oldCatalog = getCatalog();
1799
1800 // Server properties might be different
1801 // from previous connection, so initialize
1802 // again...
1803 initializePropsFromServer(this.props);
1804
1805 if (isForReconnect) {
1806 // Restore state from old connection
1807 setAutoCommit(autoCommit);
1808
1809 if (this.hasIsolationLevels) {
1810 setTransactionIsolation(oldIsolationLevel);
1811 }
1812
1813 setCatalog(oldCatalog);
1814 }
1815
1816 if (hostIndex != 0) {
1817 setFailedOverState();
1818 } else {
1819 this.failedOver = false;
1820
1821 if (hostListSize > 1) {
1822 setReadOnly(false);
1823 } else {
1824 setReadOnly(oldReadOnly);
1825 }
1826 }
1827
1828 break; // low-level connection succeeded
1829 } catch (SQLException sqlEx) {
1830 if (this.io != null) {
1831 this.io.forceClose();
1832 }
1833
1834 String sqlState = sqlEx.getSQLState();
1835
1836 if ((sqlState == null)
1837 || !sqlState.equals(
1838 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)) {
1839 throw sqlEx;
1840 }
1841
1842 if ((hostListSize - 1) == hostIndex) {
1843 throw sqlEx;
1844 }
1845 } catch (Exception unknownException) {
1846 if (this.io != null) {
1847 this.io.forceClose();
1848 }
1849
1850 if ((hostListSize - 1) == hostIndex) {
1851 throw new SQLException(
1852 "Unable to connect to any hosts due to exception: "
1853 + unknownException.toString()
1854 + (this.paranoid ? ""
1855 : Util.stackTraceToString(
1856 unknownException)),
1857 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE);
1858 }
1859 }
1860 }
1861 } else {
1862 double timeout = this.initialTimeout;
1863 boolean connectionGood = false;
1864 Exception connectionException = null;
1865
1866 for (int hostIndex = 0;
1867 (hostIndex < hostListSize) && !connectionGood;
1868 hostIndex++) {
1869 for (int attemptCount = 0;
1870 !connectionGood && (attemptCount < this.maxReconnects);
1871 attemptCount++) {
1872 try {
1873 if (this.io != null) {
1874 this.io.forceClose();
1875 }
1876
1877 String newHostPortPair = (String) this.hostList.get(hostIndex);
1878
1879 int newPort = 3306;
1880
1881 String[] hostPortPair = NonRegisteringDriver.parseHostPortPair(newHostPortPair);
1882 String newHost = hostPortPair[NonRegisteringDriver.HOST_NAME_INDEX];
1883
1884 if (newHost == null || newHost.trim().length() == 0) {
1885 newHost = "localhost";
1886 }
1887
1888 if (hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] != null) {
1889 try {
1890 newPort = Integer.parseInt(hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]);
1891 } catch (NumberFormatException nfe) {
1892 throw new SQLException(
1893 "Illegal connection port value '"
1894 + hostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] + "'",
1895 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
1896 }
1897 }
1898
1899 this.io = new MysqlIO(newHost, newPort,
1900 this.socketFactoryClassName, this.props, this,
1901 this.socketTimeout);
1902 this.io.doHandshake(this.user, this.password,
1903 this.database);
1904
1905 if (this.database.length() != 0) {
1906 this.io.sendCommand(MysqlDefs.INIT_DB,
1907 this.database, null);
1908 }
1909
1910 ping();
1911 this.isClosed = false;
1912
1913 // save state from old connection
1914 boolean autoCommit = getAutoCommit();
1915 int oldIsolationLevel = getTransactionIsolation();
1916 boolean oldReadOnly = isReadOnly();
1917 String oldCatalog = getCatalog();
1918
1919 // Server properties might be different
1920 // from previous connection, so initialize
1921 // again...
1922 initializePropsFromServer(this.props);
1923
1924 if (isForReconnect) {
1925 // Restore state from old connection
1926 setAutoCommit(autoCommit);
1927
1928 if (this.hasIsolationLevels) {
1929 setTransactionIsolation(oldIsolationLevel);
1930 }
1931
1932 setCatalog(oldCatalog);
1933 }
1934
1935 connectionGood = true;
1936
1937 if (hostIndex != 0) {
1938 setFailedOverState();
1939 } else {
1940 this.failedOver = false;
1941
1942 if (hostListSize > 1) {
1943 setReadOnly(false);
1944 } else {
1945 setReadOnly(oldReadOnly);
1946 }
1947 }
1948
1949 break;
1950 } catch (Exception EEE) {
1951 connectionException = EEE;
1952 connectionGood = false;
1953 }
1954
1955 if (!connectionGood) {
1956 try {
1957 Thread.sleep((long) timeout * 1000);
1958 timeout = timeout * 2;
1959 } catch (InterruptedException IE) {
1960 ;
1961 }
1962 }
1963 } // end attempt on hosts
1964 } // end iterator through list of hosts
1965
1966 if (!connectionGood) {
1967 // We've really failed!
1968 throw new SQLException(
1969 "Server connection failure during transaction. Due to underlying exception: '"
1970 + connectionException + "'."
1971 + (this.paranoid ? ""
1972 : Util.stackTraceToString(
1973 connectionException)) + "\nAttempted reconnect "
1974 + this.maxReconnects + " times. Giving up.",
1975 SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
1976 }
1977 }
1978
1979 if (paranoid && !highAvailability && (hostListSize <= 1)) {
1980 password = null;
1981 user = null;
1982 }
1983
1984 return newIo;
1985 }
1986
1987 /**
1988 * Closes connection and frees resources.
1989 *
1990 * @param calledExplicitly is this being called from close()
1991 * @param issueRollback should a rollback() be issued?
1992 *
1993 * @throws SQLException if an error occurs
1994 */
1995 protected void realClose(boolean calledExplicitly, boolean issueRollback)
1996 throws SQLException {
1997 if (Driver.TRACE) {
1998 Object[] args = new Object[] {
1999 new Boolean(calledExplicitly), new Boolean(issueRollback)
2000 };
2001 Debug.methodCall(this, "realClose", args);
2002 }
2003
2004 SQLException sqlEx = null;
2005
2006 if (!isClosed() && !getAutoCommit() && issueRollback) {
2007 try {
2008 rollback();
2009 } catch (SQLException ex) {
2010 sqlEx = ex;
2011 }
2012 }
2013
2014 if (this.io != null) {
2015 try {
2016 this.io.quit();
2017 } catch (Exception e) {
2018 ;
2019 }
2020
2021 this.io = null;
2022 }
2023
2024 if (this.cachedPreparedStatementParams != null) {
2025 this.cachedPreparedStatementParams.clear();
2026 this.cachedPreparedStatementParams = null;
2027 }
2028
2029 this.isClosed = true;
2030
2031 if (sqlEx != null) {
2032 throw sqlEx;
2033 }
2034 }
2035
2036 /**
2037 * Returns the locally mapped instance of a charset converter (to avoid
2038 * overhead of static synchronization).
2039 *
2040 * @param javaEncodingName the encoding name to retrieve
2041 *
2042 * @return a character converter, or null if one couldn't be mapped.
2043 */
2044 synchronized SingleByteCharsetConverter getCharsetConverter(
2045 String javaEncodingName) {
2046 SingleByteCharsetConverter converter = (SingleByteCharsetConverter) this.charsetConverterMap
2047 .get(javaEncodingName);
2048
2049 if (converter == CHARSET_CONVERTER_NOT_AVAILABLE_MARKER) {
2050 return null;
2051 }
2052
2053 if (converter == null) {
2054 try {
2055 converter = SingleByteCharsetConverter.getInstance(javaEncodingName);
2056
2057 if (converter == null) {
2058 this.charsetConverterMap.put(javaEncodingName,
2059 CHARSET_CONVERTER_NOT_AVAILABLE_MARKER);
2060 }
2061
2062 this.charsetConverterMap.put(javaEncodingName, converter);
2063 } catch (UnsupportedEncodingException unsupEncEx) {
2064 this.charsetConverterMap.put(javaEncodingName,
2065 CHARSET_CONVERTER_NOT_AVAILABLE_MARKER);
2066
2067 converter = null;
2068 }
2069 }
2070
2071 return converter;
2072 }
2073
2074 /**
2075 * Returns the maximum packet size the MySQL server will accept
2076 *
2077 * @return DOCUMENT ME!
2078 */
2079 int getMaxAllowedPacket() {
2080 return this.maxAllowedPacket;
2081 }
2082
2083 /**
2084 * DOCUMENT ME!
2085 *
2086 * @return the max rows to return for statements (by default)
2087 */
2088 int getMaxRows() {
2089 return this.maxRows;
2090 }
2091
2092 /**
2093 * Returns the Mutex all queries are locked against
2094 *
2095 * @return DOCUMENT ME!
2096 *
2097 * @throws SQLException DOCUMENT ME!
2098 */
2099 Object getMutex() throws SQLException {
2100 if (this.io == null) {
2101 throw new SQLException("Connection.close() has already been called. Invalid operation in this state.",
2102 "08003");
2103 }
2104
2105 return this.mutex;
2106 }
2107
2108 /**
2109 * Returns the packet buffer size the MySQL server reported upon connection
2110 *
2111 * @return DOCUMENT ME!
2112 */
2113 int getNetBufferLength() {
2114 return this.netBufferLength;
2115 }
2116
2117 boolean isPedantic() {
2118 return this.pedantic;
2119 }
2120
2121 void setReadInfoMsgEnabled(boolean flag) {
2122 this.readInfoMsg = flag;
2123 }
2124
2125 boolean isReadInfoMsgEnabled() {
2126 return this.readInfoMsg;
2127 }
2128
2129 int getServerMajorVersion() {
2130 return this.io.getServerMajorVersion();
2131 }
2132
2133 int getServerMinorVersion() {
2134 return this.io.getServerMinorVersion();
2135 }
2136
2137 int getServerSubMinorVersion() {
2138 return this.io.getServerSubMinorVersion();
2139 }
2140
2141 String getServerVersion() {
2142 return this.io.getServerVersion();
2143 }
2144
2145 String getURL() {
2146 return this.myURL;
2147 }
2148
2149 /**
2150 * Set whether or not this connection should use SSL
2151 *
2152 * @param flag DOCUMENT ME!
2153 */
2154 void setUseSSL(boolean flag) {
2155 this.useSSL = flag;
2156 }
2157
2158 String getUser() {
2159 return this.user;
2160 }
2161
2162 boolean alwaysClearStream() {
2163 return this.alwaysClearStream;
2164 }
2165
2166 boolean continueBatchOnError() {
2167 return this.continueBatchOnError;
2168 }
2169
2170 /**
2171 * Send a query to the server. Returns one of the ResultSet objects. This
2172 * is synchronized, so Statement's queries will be serialized.
2173 *
2174 * @param sql the SQL statement to be executed
2175 * @param maxRowsToRetreive DOCUMENT ME!
2176 * @param catalog DOCUMENT ME!
2177 *
2178 * @return a ResultSet holding the results
2179 *
2180 * @exception java.sql.SQLException if a database error occurs
2181 */
2182 ResultSet execSQL(String sql, int maxRowsToRetreive, String catalog)
2183 throws java.sql.SQLException {
2184 if (Driver.TRACE) {
2185 Object[] args = { sql, new Integer(maxRowsToRetreive) };
2186 Debug.methodCall(this, "execSQL", args);
2187 }
2188
2189 return execSQL(sql, maxRowsToRetreive, null,
2190 java.sql.ResultSet.CONCUR_READ_ONLY, catalog);
2191 }
2192
2193 ResultSet execSQL(String sql, int maxRows, int resultSetType,
2194 boolean streamResults, boolean queryIsSelectOnly, String catalog)
2195 throws SQLException {
2196 return execSQL(sql, maxRows, null, resultSetType, streamResults,
2197 queryIsSelectOnly, catalog);
2198 }
2199
2200 ResultSet execSQL(String sql, int maxRows, Buffer packet, String catalog)
2201 throws java.sql.SQLException {
2202 return execSQL(sql, maxRows, packet,
2203 java.sql.ResultSet.CONCUR_READ_ONLY, catalog);
2204 }
2205
2206 ResultSet execSQL(String sql, int maxRows, Buffer packet,
2207 int resultSetType, String catalog) throws java.sql.SQLException {
2208 return execSQL(sql, maxRows, packet, resultSetType, true, false, catalog);
2209 }
2210
2211 ResultSet execSQL(String sql, int maxRows, Buffer packet,
2212 int resultSetType, boolean streamResults, boolean queryIsSelectOnly,
2213 String catalog) throws java.sql.SQLException {
2214 if (Driver.TRACE) {
2215 Object[] args = { sql, new Integer(maxRows), packet };
2216 Debug.methodCall(this, "execSQL", args);
2217 }
2218
2219 if ((sql == null) || (sql.length() == 0)) {
2220 if (packet == null) {
2221 throw new SQLException("Query can not be null or empty",
2222 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2223 }
2224 }
2225
2226 //
2227 // Fall-back if the master is back online if we've
2228 // issued queriesBeforeRetryMaster queries since
2229 // we failed over
2230 //
2231 synchronized (this.mutex) {
2232 this.lastQueryFinishedTime = 0; // we're busy!
2233
2234 if ((this.highAvailability || this.failedOver) && this.needsPing) {
2235 pingAndReconnect(false);
2236 }
2237
2238 try {
2239 int realMaxRows = (maxRows == -1) ? MysqlDefs.MAX_ROWS : maxRows;
2240
2241 if (packet == null) {
2242 String encoding = null;
2243
2244 if (useUnicode()) {
2245 encoding = getEncoding();
2246 }
2247
2248 return this.io.sqlQuery(sql, realMaxRows, encoding, this,
2249 resultSetType, streamResults, catalog);
2250 } else {
2251 return this.io.sqlQueryDirect(packet, realMaxRows, this,
2252 resultSetType, streamResults, catalog);
2253 }
2254 } catch (java.sql.SQLException sqlE) {
2255 // don't clobber SQL exceptions
2256 String sqlState = sqlE.getSQLState();
2257
2258 if (this.highAvailability || this.failedOver) {
2259 this.needsPing = true;
2260 } else if ((sqlState != null)
2261 && sqlState.equals(
2262 SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE)) {
2263 cleanup(sqlE);
2264 }
2265
2266 throw sqlE;
2267 } catch (Exception ex) {
2268 if (this.highAvailability || this.failedOver) {
2269 this.needsPing = true;
2270 } else if (ex instanceof IOException) {
2271 cleanup(ex);
2272 }
2273
2274 String exceptionType = ex.getClass().getName();
2275 String exceptionMessage = ex.getMessage();
2276
2277 if (!this.useParanoidErrorMessages()) {
2278 exceptionMessage += "\n\nNested Stack Trace:\n";
2279 exceptionMessage += Util.stackTraceToString(ex);
2280 }
2281
2282 throw new java.sql.SQLException(
2283 "Error during query: Unexpected Exception: "
2284 + exceptionType + " message given: " + exceptionMessage,
2285 SQLError.SQL_STATE_GENERAL_ERROR);
2286 } finally {
2287 this.lastQueryFinishedTime = System.currentTimeMillis();
2288 }
2289 }
2290 }
2291
2292 /**
2293 * Has the maxRows value changed?
2294 *
2295 * @param stmt DOCUMENT ME!
2296 */
2297 void maxRowsChanged(Statement stmt) {
2298 synchronized (this.mutex) {
2299 if (this.statementsUsingMaxRows == null) {
2300 this.statementsUsingMaxRows = new HashMap();
2301 }
2302
2303 this.statementsUsingMaxRows.put(stmt, stmt);
2304
2305 this.maxRowsChanged = true;
2306 }
2307 }
2308
2309 /**
2310 * Called by statements on their .close() to let the connection know when
2311 * it is safe to set the connection back to 'default' row limits.
2312 *
2313 * @param stmt the statement releasing it's max-rows requirement
2314 *
2315 * @throws SQLException if a database error occurs issuing the statement
2316 * that sets the limit default.
2317 */
2318 void unsetMaxRows(Statement stmt) throws SQLException {
2319 synchronized (this.mutex) {
2320 if (this.statementsUsingMaxRows != null) {
2321 Object found = this.statementsUsingMaxRows.remove(stmt);
2322
2323 if ((found != null)
2324 && (this.statementsUsingMaxRows.size() == 0)) {
2325 execSQL("SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1,
2326 this.database);
2327 this.maxRowsChanged = false;
2328 }
2329 }
2330 }
2331 }
2332
2333 boolean useAnsiQuotedIdentifiers() {
2334 return this.useAnsiQuotes;
2335 }
2336
2337 boolean useHostsInPrivileges() {
2338 return this.useHostsInPrivileges;
2339 }
2340
2341 /**
2342 * Has maxRows() been set?
2343 *
2344 * @return DOCUMENT ME!
2345 */
2346 boolean useMaxRows() {
2347 synchronized (this.mutex) {
2348 return this.maxRowsChanged;
2349 }
2350 }
2351
2352 boolean useStreamLengthsInPrepStmts() {
2353 return this.useStreamLengthsInPrepStmts;
2354 }
2355
2356 /**
2357 * Sets state for a failed-over connection
2358 *
2359 * @throws SQLException DOCUMENT ME!
2360 */
2361 private void setFailedOverState() throws SQLException {
2362 if (this.failOverReadOnly) {
2363 setReadOnly(true);
2364 }
2365
2366 this.queriesIssuedFailedOver = 0;
2367 this.failedOver = true;
2368 this.masterFailTimeMillis = System.currentTimeMillis();
2369 }
2370
2371 /**
2372 * Builds the map needed for 4.1.0 and newer servers that maps field-level
2373 * charset/collation info to a java character encoding name.
2374 *
2375 * @throws SQLException DOCUMENT ME!
2376 */
2377 private void buildCollationMapping() throws SQLException {
2378 if (this.io.versionMeetsMinimum(4, 1, 0)) {
2379 com.mysql.jdbc.Statement stmt = null;
2380 com.mysql.jdbc.ResultSet results = null;
2381
2382 TreeMap sortedCollationMap = new TreeMap();
2383
2384 try {
2385 stmt = (com.mysql.jdbc.Statement) createStatement();
2386
2387 if (stmt.getMaxRows() != 0) {
2388 stmt.setMaxRows(0);
2389 }
2390
2391 results = (com.mysql.jdbc.ResultSet) stmt.executeQuery(
2392 "SHOW COLLATION");
2393
2394 while (results.next()) {
2395 String charsetName = results.getString(2);
2396 Integer charsetIndex = new Integer(results.getInt(3));
2397
2398 sortedCollationMap.put(charsetIndex, charsetName);
2399 }
2400
2401 // Now, merge with what we already know
2402 int highestIndex = ((Integer) sortedCollationMap.lastKey())
2403 .intValue();
2404
2405 if (CharsetMapping.INDEX_TO_CHARSET.length > highestIndex) {
2406 highestIndex = CharsetMapping.INDEX_TO_CHARSET.length;
2407 }
2408
2409 this.indexToCharsetMapping = new String[highestIndex + 1];
2410
2411 for (int i = 0; i < CharsetMapping.INDEX_TO_CHARSET.length;
2412 i++) {
2413 this.indexToCharsetMapping[i] = CharsetMapping.INDEX_TO_CHARSET[i];
2414 }
2415
2416 for (Iterator indexIter = sortedCollationMap.entrySet()
2417 .iterator();
2418 indexIter.hasNext();) {
2419 Map.Entry indexEntry = (Map.Entry) indexIter.next();
2420
2421 String mysqlCharsetName = (String) indexEntry.getValue();
2422
2423 this.indexToCharsetMapping[((Integer) indexEntry.getKey())
2424 .intValue()] = (String) CharsetMapping.MYSQL_TO_JAVA_CHARSET_MAP
2425 .get(mysqlCharsetName);
2426 }
2427 } catch (java.sql.SQLException e) {
2428 throw e;
2429 } finally {
2430 if (results != null) {
2431 try {
2432 results.close();
2433 } catch (java.sql.SQLException sqlE) {
2434 ;
2435 }
2436 }
2437
2438 if (stmt != null) {
2439 try {
2440 stmt.close();
2441 } catch (java.sql.SQLException sqlE) {
2442 ;
2443 }
2444 }
2445 }
2446 } else {
2447 // Safety, we already do this as an initializer, but this makes
2448 // the intent more clear
2449 this.indexToCharsetMapping = CharsetMapping.INDEX_TO_CHARSET;
2450 }
2451 }
2452
2453 private void checkClosed() throws SQLException {
2454 if (this.isClosed) {
2455 StringBuffer exceptionMessage = new StringBuffer();
2456
2457 exceptionMessage.append(
2458 "No operations allowed after connection closed.");
2459
2460 if (!this.paranoid) {
2461 if (this.forcedCloseReason != null) {
2462 exceptionMessage.append(
2463 "\n\nConnection was closed due to the following exception:");
2464 exceptionMessage.append(Util.stackTraceToString(
2465 this.forcedCloseReason));
2466 } else if (this.explicitCloseLocation != null) {
2467 exceptionMessage.append(
2468 "\n\nConnection was closed explicitly by the application at the following location:");
2469 exceptionMessage.append(Util.stackTraceToString(
2470 this.explicitCloseLocation));
2471 }
2472 }
2473
2474 throw new SQLException(exceptionMessage.toString(), "08003");
2475 }
2476 }
2477
2478 /**
2479 * If useUnicode flag is set and explicit client character encoding isn't
2480 * specified then assign encoding from server if any.
2481 *
2482 * @throws SQLException DOCUMENT ME!
2483 */
2484 private void checkServerEncoding() throws SQLException {
2485 if (this.doUnicode && (this.encoding != null)) {
2486 // spec'd by client, don't map, but check
2487 return;
2488 }
2489
2490 this.mysqlEncodingName = (String) this.serverVariables.get(
2491 "character_set");
2492
2493 String javaEncodingName = null;
2494
2495 if (this.mysqlEncodingName != null) {
2496 javaEncodingName = (String) charsetMap.get(this.mysqlEncodingName
2497 .toUpperCase());
2498 }
2499
2500 //
2501 // First check if we can do the encoding ourselves
2502 //
2503 if (!this.doUnicode && (javaEncodingName != null)) {
2504 SingleByteCharsetConverter converter = getCharsetConverter(javaEncodingName);
2505
2506 if (converter != null) { // we know how to convert this ourselves
2507 this.doUnicode = true; // force the issue
2508 this.encoding = javaEncodingName;
2509
2510 return;
2511 }
2512 }
2513
2514 //
2515 // Now, try and find a Java I/O converter that can do
2516 // the encoding for us
2517 //
2518 if (this.mysqlEncodingName != null) {
2519 if (javaEncodingName == null) {
2520 // We don't have a mapping for it, so try
2521 // and canonicalize the name....
2522 if (Character.isLowerCase(this.mysqlEncodingName.charAt(0))) {
2523 char[] ach = this.mysqlEncodingName.toCharArray();
2524 ach[0] = Character.toUpperCase(this.mysqlEncodingName
2525 .charAt(0));
2526 this.encoding = new String(ach);
2527 }
2528 }
2529
2530 //
2531 // Attempt to use the encoding, and bail out if it
2532 // can't be used
2533 //
2534 try {
2535 "abc".getBytes(javaEncodingName);
2536 this.encoding = javaEncodingName;
2537 this.doUnicode = true;
2538 } catch (UnsupportedEncodingException UE) {
2539 throw new SQLException(
2540 "The driver can not map the character encoding '"
2541 + this.encoding + "' that your server is using "
2542 + "to a character encoding your JVM understands. You "
2543 + "can specify this mapping manually by adding \"useUnicode=true\" "
2544 + "as well as \"characterEncoding=[an_encoding_your_jvm_understands]\" "
2545 + "to your JDBC URL.",
2546 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
2547 }
2548 }
2549 }
2550
2551 /**
2552 * Set transaction isolation level to the value received from server if
2553 * any. Is called by connectionInit(...)
2554 *
2555 * @throws SQLException DOCUMENT ME!
2556 */
2557 private void checkTransactionIsolationLevel() throws SQLException {
2558 String txIsolationName = null;
2559
2560 if (this.io.versionMeetsMinimum(4, 0, 3)) {
2561 txIsolationName = "tx_isolation";
2562 } else {
2563 txIsolationName = "transaction_isolation";
2564 }
2565
2566 String s = (String) this.serverVariables.get(txIsolationName);
2567
2568 if (s != null) {
2569 Integer intTI = (Integer) mapTransIsolationName2Value.get(s);
2570
2571 if (intTI != null) {
2572 isolationLevel = intTI.intValue();
2573 }
2574 }
2575 }
2576
2577 /**
2578 * Destroys this connection and any underlying resources
2579 *
2580 * @param cleanupReason DOCUMENT ME!
2581 */
2582 private void cleanup(Throwable cleanupReason) {
2583 try {
2584 if ((this.io != null) && !isClosed()) {
2585 realClose(false, false);
2586 } else if (this.io != null) {
2587 this.io.forceClose();
2588 }
2589 } catch (SQLException sqlEx) {
2590 // ignore, we're going away.
2591 }
2592
2593 this.isClosed = true;
2594 this.forcedCloseReason = cleanupReason;
2595 }
2596
2597 /**
2598 * Sets up client character set for MySQL-4.1 and newer. This
2599 * must be done before any further communication with the server!
2600 *
2601 * @return true if this routine actually configured the client character
2602 * set, or false if the driver needs to use 'older' methods to
2603 * detect the character set, as it is connected to a MySQL server
2604 * older than 4.1.0
2605 *
2606 * @throws SQLException if an exception happens while sending 'SET NAMES'
2607 * to the server, or the server sends character set information
2608 * that the client doesn't know about.
2609 */
2610 private boolean configureClientCharacterSet() throws SQLException {
2611 String realJavaEncoding = getEncoding();
2612 boolean characterSetAlreadyConfigured = false;
2613
2614 try {
2615 if (this.io.versionMeetsMinimum(4, 1, 0)) {
2616
2617 characterSetAlreadyConfigured = true;
2618
2619 this.doUnicode = true;
2620
2621 configureCharsetProperties(this.props);
2622
2623 realJavaEncoding = getEncoding(); // we need to do this again to grab this for
2624 // versions > 4.1.0
2625
2626 try {
2627 this.encoding = CharsetMapping.INDEX_TO_CHARSET[this.io.serverCharsetIndex];
2628 } catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
2629 if (realJavaEncoding != null) {
2630 // user knows best, try it
2631 this.encoding = realJavaEncoding;
2632 } else {
2633 throw new SQLException(
2634 "Unknown initial character set index '"
2635 + this.io.serverCharsetIndex
2636 + "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
2637 SQLError.SQL_STATE_GENERAL_ERROR);
2638 }
2639 }
2640
2641 if (this.encoding == null) {
2642 // punt?
2643 this.encoding = "ISO8859_1";
2644 }
2645
2646 //
2647 // Has the user has 'forced' the character encoding via
2648 // driver properties?
2649 //
2650 if (useUnicode()) {
2651 if (realJavaEncoding != null) {
2652 if ("ISO8859_2".equals(realJavaEncoding)
2653 && (this.mysqlEncodingName == null)) {
2654 throw new SQLException(
2655 "Character encoding 'ISO8859_2' specified in JDBC URL which maps to multiple MySQL character encodings:"
2656 + "\n\n" + "* 'latin2'\n" + "* 'czech'\n"
2657 + "* 'hungarian'\n" + "* 'croat'\n"
2658 + "\nSpecify one of the above encodings using the 'mysqlEncoding' connection property.",
2659 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
2660 } else if ("ISO8859_13".equals(realJavaEncoding)
2661 && (this.mysqlEncodingName == null)) {
2662 throw new SQLException(
2663 "Character encoding 'ISO8859_13' specified in JDBC URL which maps to multiple MySQL character encodings:"
2664 + "\n\n" + "* 'latvian'\n" + "* 'latvian1'\n"
2665 + "* 'estonia'\n"
2666 + "\nSpecify one of the above encodings using the 'mysqlEncoding' connection property.",
2667 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
2668 }
2669
2670 if (this.mysqlEncodingName == null) {
2671 this.mysqlEncodingName = (String) CharsetMapping.JAVA_UC_TO_MYSQL_CHARSET_MAP
2672 .get(realJavaEncoding.toUpperCase());
2673 }
2674
2675 //
2676 // Now, inform the server what character set we
2677 // will be using from now-on...
2678 //
2679 if (realJavaEncoding.equalsIgnoreCase("UTF-8")
2680 || realJavaEncoding.equalsIgnoreCase("UTF8")) {
2681 // charset names are case-sensitive
2682 execSQL("SET NAMES utf8", -1, this.database);
2683
2684 // Switch driver's encoding now, since the server
2685 // knows what we're sending...
2686 this.encoding = realJavaEncoding;
2687 } else {
2688 String namesEncoding = this.mysqlEncodingName;
2689
2690 if ("koi8_ru".equals(this.mysqlEncodingName)) {
2691 // This has a _different_ name in 4.1...
2692 namesEncoding = "ko18r";
2693 }
2694
2695 if (namesEncoding != null) {
2696 execSQL("SET NAMES " + namesEncoding, -1,
2697 this.database);
2698 }
2699
2700 // Switch driver's encoding now, since the server
2701 // knows what we're sending...
2702 this.encoding = realJavaEncoding;
2703 }
2704 } else if (this.encoding != null) {
2705 // Tell the server we'll use the server default charset to send our
2706 // queries from now on....
2707 this.mysqlEncodingName = (String) CharsetMapping.JAVA_UC_TO_MYSQL_CHARSET_MAP
2708 .get(this.encoding.toUpperCase());
2709
2710 execSQL("SET NAMES " + this.mysqlEncodingName, -1, this.database);
2711
2712 realJavaEncoding = this.encoding;
2713 }
2714 }
2715
2716 //
2717 // We know how to deal with any charset coming back from
2718 // the database, so tell the server not to do conversion
2719 // if the user hasn't 'forced' a result-set character set
2720 //
2721
2722 if (this.io.versionMeetsMinimum(4, 1, 1)) {
2723 if (this.characterSetResults == null) {
2724 execSQL("SET character_set_results = NULL", -1, this.database);
2725 } else {
2726 StringBuffer setBuf = new StringBuffer("SET character_set_results = ".length() + this.characterSetResults.length());
2727 setBuf.append("SET character_set_results = ").append(this.characterSetResults);
2728
2729 execSQL(setBuf.toString(), -1, this.database);
2730 }
2731 }
2732 } else {
2733 // Use what the server has specified
2734 realJavaEncoding = this.encoding; // so we don't get
2735 // swapped out in the finally
2736 // block....
2737 }
2738
2739
2740 } finally {
2741 // Failsafe, make sure that the driver's notion of character
2742 // encoding matches what the user has specified.
2743 this.encoding = realJavaEncoding;
2744 }
2745
2746 return characterSetAlreadyConfigured;
2747 }
2748
2749 /**
2750 * The character set we want results and result metadata
2751 * returned in (null == results in any charset, metadata
2752 * in UTF-8).
2753 */
2754 private String characterSetResults = null;
2755
2756 /**
2757 * The character set we want results and result metadata
2758 * returned in (null == results in any charset, metadata
2759 * in UTF-8).
2760 */
2761 private String characterSetResultsOnServer = null;
2762
2763 /**
2764 * For servers > 4.1.0, what character set is the metadata
2765 * returned in?
2766 */
2767 private String characterSetMetadata = null;
2768
2769 /**
2770 * Should rollback() be called when pooled connections are closed?
2771 */
2772 private boolean rollbackOnPooledClose = true;
2773
2774 private boolean tinyint1isBit;
2775
2776 /**
2777 * Configures the client's timezone if required.
2778 *
2779 * @throws SQLException if the timezone the server is configured to use
2780 * can't be mapped to a Java timezone.
2781 */
2782 private void configureTimezone() throws SQLException {
2783 String configuredTimeZoneOnServer = (String)this.serverVariables.get("timezone");
2784
2785 if (configuredTimeZoneOnServer == null) {
2786 configuredTimeZoneOnServer = (String)this.serverVariables.get("time_zone");
2787
2788 if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
2789 configuredTimeZoneOnServer = (String)this.serverVariables.get("system_time_zone");
2790 }
2791 }
2792
2793 if (this.useTimezone && configuredTimeZoneOnServer != null) {
2794 // user can specify/override as property
2795 String canoncicalTimezone = this.props.getProperty("serverTimezone");
2796
2797 if ((canoncicalTimezone == null)
2798 || (canoncicalTimezone.length() == 0)) {
2799 String serverTimezoneStr = configuredTimeZoneOnServer;
2800
2801 try {
2802 canoncicalTimezone = TimeUtil.getCanoncialTimezone(serverTimezoneStr);
2803
2804 if (canoncicalTimezone == null) {
2805 throw new SQLException("Can't map timezone '"
2806 + serverTimezoneStr + "' to "
2807 + " canonical timezone.",
2808 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2809 }
2810 } catch (IllegalArgumentException iae) {
2811 throw new SQLException(iae.getMessage(),
2812 SQLError.SQL_STATE_GENERAL_ERROR);
2813 }
2814 }
2815
2816 serverTimezone = TimeZone.getTimeZone(canoncicalTimezone);
2817
2818 //
2819 // The Calendar class has the behavior of mapping
2820 // unknown timezones to 'GMT' instead of throwing an
2821 // exception, so we must check for this...
2822 //
2823 if (!canoncicalTimezone.equalsIgnoreCase("GMT")
2824 && serverTimezone.getID().equals("GMT")) {
2825 throw new SQLException("No timezone mapping entry for '"
2826 + canoncicalTimezone + "'",
2827 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2828 }
2829 }
2830 }
2831
2832 private void detectFloatingPointStyle() throws SQLException {
2833 java.sql.Statement stmt = null;
2834 java.sql.ResultSet rs = null;
2835
2836 try {
2837 stmt = createStatement();
2838
2839 if (stmt.getMaxRows() != 0) {
2840 stmt.setMaxRows(0);
2841 }
2842
2843 rs = stmt.executeQuery(
2844 "select round('inf'), round('-inf'), round('nan')");
2845
2846 if (rs.next()) {
2847 String posInf = rs.getString(1);
2848
2849 if ("inf".equalsIgnoreCase(posInf)) {
2850 this.positiveInfinityRep = "'inf'";
2851 this.positiveInfinityRepIsClipped = false;
2852 }
2853
2854 String negInf = rs.getString(2);
2855
2856 if ("-inf".equalsIgnoreCase(negInf)) {
2857 this.negativeInfinityRep = "'-inf'";
2858 this.negativeInfinityRepIsClipped = false;
2859 }
2860
2861 String nan = rs.getString(3);
2862
2863 if ("nan".equalsIgnoreCase(nan)) {
2864 this.notANumberRep = "'nan'";
2865 this.notANumberRepIsClipped = false;
2866 }
2867 }
2868
2869 rs.close();
2870 rs = null;
2871
2872 stmt.close();
2873 stmt = null;
2874 } catch (SQLException sqlEx) {
2875 ; // ignore here, we default to lowest-common denominator
2876 } finally {
2877 if (rs != null) {
2878 try {
2879 rs.close();
2880 } catch (SQLException sqlEx) {
2881 ; // ignore
2882 }
2883
2884 rs = null;
2885 }
2886
2887 if (stmt != null) {
2888 try {
2889 stmt.close();
2890 } catch (SQLException sqlEx) {
2891 ; // ignore
2892 }
2893
2894 stmt = null;
2895 }
2896 }
2897 }
2898
2899 /**
2900 * Initializes driver properties that come from URL or properties passed to
2901 * the driver manager.
2902 *
2903 * @param info DOCUMENT ME!
2904 *
2905 * @throws SQLException DOCUMENT ME!
2906 */
2907 private void initializeDriverProperties(Properties info)
2908 throws SQLException {
2909
2910 if (info.getProperty("tinyInt1isBit") != null) {
2911 this.tinyint1isBit = ("TRUE".equalsIgnoreCase(info.getProperty("tinyInt1isBit")));
2912 } else {
2913 this.tinyint1isBit = true;
2914 }
2915
2916 this.useOnlyServerErrorMessages = ("TRUE".equalsIgnoreCase(info.getProperty("useOnlyServerErrorMessages")));
2917
2918 // This property has a 'default', so need to use long-form
2919 if (info.getProperty("rollbackOnPooledClose") != null) {
2920 this.rollbackOnPooledClose = "TRUE".equalsIgnoreCase(info.getProperty("rollbackOnPooledClose"));
2921 }
2922
2923 this.socketFactoryClassName = info.getProperty("socketFactory",
2924 DEFAULT_SOCKET_FACTORY);
2925
2926 this.failOverReadOnly = "TRUE".equalsIgnoreCase(info.getProperty(
2927 "failOverReadOnly"));
2928
2929 if (info.getProperty("useUnbufferedInput") != null) {
2930 this.useUnbufferedInput = "TRUE".equalsIgnoreCase(info.getProperty(
2931 "useUnbufferedInput"));
2932 }
2933
2934 if (info.getProperty("cachePrepStmts") != null) {
2935 this.cachePreparedStatements = info.getProperty("cachePrepStmts")
2936 .equalsIgnoreCase("TRUE");
2937
2938 if (this.cachePreparedStatements) {
2939 if (info.getProperty("prepStmtCacheSize") != null) {
2940 try {
2941 this.preparedStatementCacheSize = Integer.parseInt(info
2942 .getProperty("prepStmtCacheSize"));
2943
2944 if (this.preparedStatementCacheSize < 0) {
2945 throw new SQLException("Connection property 'prepStmtCacheSize' must be a non-negative integer value.",
2946 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2947 }
2948 } catch (NumberFormatException nfe) {
2949 throw new SQLException("Connection property 'prepStmtCacheSize' must be a non-negative integer value.",
2950 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2951 }
2952 }
2953
2954 if (info.getProperty("prepStmtCacheSqlLimit") != null) {
2955 try {
2956 this.preparedStatementCacheMaxSqlSize = Integer
2957 .parseInt(info.getProperty("prepStmtCacheSqlLimit"));
2958
2959 if (this.preparedStatementCacheMaxSqlSize < 0) {
2960 throw new SQLException("Connection property 'prepStmtCacheSqlLimit' must be a non-negative integer value.",
2961 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2962 }
2963 } catch (NumberFormatException nfe) {
2964 throw new SQLException("Connection property 'prepStmtCacheSqlLimit' must be a non-negative integer value.",
2965 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2966 }
2967 }
2968
2969 this.cachedPreparedStatementParams = new HashMap(this.preparedStatementCacheSize);
2970 }
2971 }
2972
2973 if (info.getProperty("alwaysClearStream") != null) {
2974 this.alwaysClearStream = info.getProperty("alwaysClearStream")
2975 .equalsIgnoreCase("TRUE");
2976 }
2977
2978 if (info.getProperty("reconnectAtTxEnd") != null) {
2979 this.reconnectAtTxEnd = info.getProperty("reconnectAtTxEnd")
2980 .equalsIgnoreCase("TRUE");
2981 }
2982
2983 if (info.getProperty("clobberStreamingResults") != null) {
2984 this.clobberStreamingResults = info.getProperty(
2985 "clobberStreamingResults").equalsIgnoreCase("TRUE");
2986 }
2987
2988 if (info.getProperty("strictUpdates") != null) {
2989 this.strictUpdates = info.getProperty("strictUpdates")
2990 .equalsIgnoreCase("TRUE");
2991 }
2992
2993 if (info.getProperty("ignoreNonTxTables") != null) {
2994 this.ignoreNonTxTables = info.getProperty("ignoreNonTxTables")
2995 .equalsIgnoreCase("TRUE");
2996 }
2997
2998 if (info.getProperty("secondsBeforeRetryMaster") != null) {
2999 String secondsBeforeRetryStr = info.getProperty(
3000 "secondsBeforeRetryMaster");
3001
3002 try {
3003 int seconds = Integer.parseInt(secondsBeforeRetryStr);
3004
3005 if (seconds < 1) {
3006 throw new SQLException("Illegal (< 1) value '"
3007 + secondsBeforeRetryStr
3008 + "' for 'secondsBeforeRetryMaster'",
3009 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3010 }
3011
3012 this.secondsBeforeRetryMaster = seconds;
3013 } catch (NumberFormatException nfe) {
3014 throw new SQLException("Illegal non-numeric value '"
3015 + secondsBeforeRetryStr
3016 + "' for 'secondsBeforeRetryMaster'",
3017 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3018 }
3019 }
3020
3021 if (info.getProperty("queriesBeforeRetryMaster") != null) {
3022 String queriesBeforeRetryStr = info.getProperty(
3023 "queriesBeforeRetryMaster");
3024
3025 try {
3026 this.queriesBeforeRetryMaster = Integer.parseInt(queriesBeforeRetryStr);
3027 } catch (NumberFormatException nfe) {
3028 throw new SQLException("Illegal non-numeric value '"
3029 + queriesBeforeRetryStr
3030 + "' for 'queriesBeforeRetryMaster'",
3031 SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3032 }
3033 }
3034
3035 if (info.getProperty("allowLoadLocalInfile") != null) {
3036 this.allowLoadLocalInfile = info.getProperty("allowLoadLocalInfile")
3037 .equalsIgnoreCase("TRUE");
3038 }
3039
3040 if (info.getProperty("continueBatchOnError") != null) {
3041 this.continueBatchOnError = info.getProperty("continueBatchOnError")
3042 .equalsIgnoreCase("TRUE");
3043 }
3044
3045 if (info.getProperty("pedantic") != null) {
3046 this.pedantic = info.getProperty("pedantic").equalsIgnoreCase("TRUE");
3047 }
3048
3049 if (info.getProperty("useStreamLengthsInPrepStmts") != null) {
3050 this.useStreamLengthsInPrepStmts = info.getProperty(
3051 "useStreamLengthsInPrepStmts").equalsIgnoreCase("TRUE");
3052 }
3053
3054 if (info.getProperty("useTimezone") != null) {
3055 this.useTimezone = info.getProperty("useTimezone").equalsIgnoreCase("TRUE");
3056 }
3057
3058 if (info.getProperty("relaxAutoCommit") != null) {
3059 this.relaxAutoCommit = info.getProperty("relaxAutoCommit")
3060 .equalsIgnoreCase("TRUE");
3061 } else if (info.getProperty("relaxAutocommit") != null) {
3062 this.relaxAutoCommit = info.getProperty("relaxAutocommit")
3063 .equalsIgnoreCase("TRUE");
3064 }
3065
3066 if (info.getProperty("paranoid") != null) {
3067 this.paranoid = info.getProperty("paranoid").equalsIgnoreCase("TRUE");
3068 }
3069
3070 if (info.getProperty("autoReconnect") != null) {
3071 this.highAvailability = info.getProperty("autoReconnect")
3072 .equalsIgnoreCase("TRUE");
3073 }
3074
3075 if (info.getProperty("capitalizeTypeNames") != null) {
3076 this.capitalizeDBMDTypes = info.getProperty("capitalizeTypeNames")
3077 .equalsIgnoreCase("TRUE");
3078 }
3079
3080 if (info.getProperty("ultraDevHack") != null) {
3081 this.useUltraDevWorkAround = info.getProperty("ultraDevHack")
3082 .equalsIgnoreCase("TRUE");
3083 }
3084
3085 if (info.getProperty("strictFloatingPoint") != null) {
3086 this.strictFloatingPoint = info.getProperty("strictFloatingPoint")
3087 .equalsIgnoreCase("TRUE");
3088 }
3089
3090 if (info.getProperty("useSSL") != null) {
3091 this.useSSL = info.getProperty("useSSL").equalsIgnoreCase("TRUE");
3092 }
3093
3094 if (info.getProperty("useCompression") != null) {
3095 this.useCompression = info.getProperty("useCompression")
3096 .equalsIgnoreCase("TRUE");
3097 }
3098
3099 if (info.getProperty("socketTimeout") != null) {
3100 try {
3101 int n = Integer.parseInt(info.getProperty("socketTimeout"));
3102
3103 if (n < 0) {
3104 throw new SQLException("socketTimeout can not " + "be < 0",
3105 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3106 }
3107
3108 this.socketTimeout = n;
3109 } catch (NumberFormatException NFE) {
3110 throw new SQLException("Illegal parameter '"
3111 + info.getProperty("socketTimeout") + "' for socketTimeout",
3112 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3113 }
3114 }
3115
3116 if (this.highAvailability) {
3117 if (info.getProperty("maxReconnects") != null) {
3118 try {
3119 int n = Integer.parseInt(info.getProperty("maxReconnects"));
3120 this.maxReconnects = n;
3121 } catch (NumberFormatException NFE) {
3122 throw new SQLException("Illegal parameter '"
3123 + info.getProperty("maxReconnects")
3124 + "' for maxReconnects",
3125 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3126 }
3127 }
3128
3129 if (info.getProperty("initialTimeout") != null) {
3130 try {
3131 double n = Integer.parseInt(info.getProperty(
3132 "initialTimeout"));
3133 this.initialTimeout = n;
3134 } catch (NumberFormatException NFE) {
3135 throw new SQLException("Illegal parameter '"
3136 + info.getProperty("initialTimeout")
3137 + "' for initialTimeout",
3138 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3139 }
3140 }
3141 }
3142
3143 if (info.getProperty("maxRows") != null) {
3144 try {
3145 int n = Integer.parseInt(info.getProperty("maxRows"));
3146
3147 if (n == 0) {
3148 n = -1;
3149 }
3150
3151 // adjust so that it will become MysqlDefs.MAX_ROWS
3152 // in execSQL()
3153 this.maxRows = n;
3154 this.maxRowsChanged = true;
3155 } catch (NumberFormatException NFE) {
3156 throw new SQLException("Illegal parameter '"
3157 + info.getProperty("maxRows") + "' for maxRows",
3158 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3159 }
3160 }
3161
3162 if (info.getProperty("useHostsInPrivileges") != null) {
3163 this.useHostsInPrivileges = info.getProperty("useHostsInPrivileges")
3164 .equalsIgnoreCase("TRUE");
3165 }
3166
3167 if (info.getProperty("interactiveClient") != null) {
3168 this.isInteractiveClient = info.getProperty("interactiveClient")
3169 .equalsIgnoreCase("TRUE");
3170 }
3171
3172 if (info.getProperty("useUnicode") != null) {
3173 this.doUnicode = info.getProperty("useUnicode").equalsIgnoreCase("TRUE");
3174 }
3175
3176
3177 if (this.doUnicode) {
3178 configureCharsetProperties(info);
3179 }
3180 }
3181
3182 /**
3183 * Configures client-side properties for character set information.
3184 *
3185 * @param info the properties passed during connection
3186 *
3187 * @throws SQLException if unable to configure the specified character set.
3188 */
3189 private void configureCharsetProperties(Properties info) throws SQLException {
3190 if (info.getProperty("mysqlEncoding") != null) {
3191 this.mysqlEncodingName = info.getProperty("mysqlEncoding");
3192 }
3193
3194 if (info.getProperty("characterEncoding") != null) {
3195 this.encoding = info.getProperty("characterEncoding");
3196
3197 // Attempt to use the encoding, and bail out if it
3198 // can't be used
3199 try {
3200 String testString = "abc";
3201 testString.getBytes(this.encoding);
3202 } catch (UnsupportedEncodingException UE) {
3203 // Try the MySQL character encoding, then....
3204 String oldEncoding = this.encoding;
3205
3206 this.encoding = (String)CharsetMapping.MYSQL_TO_JAVA_CHARSET_MAP.get(oldEncoding);
3207
3208 if (this.encoding == null) {
3209 throw new SQLException("Java does not support the MySQL character encoding " +
3210 " "
3211 + "encoding '" + oldEncoding + "'.",
3212 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3213 }
3214
3215 try {
3216 String testString = "abc";
3217 testString.getBytes(this.encoding);
3218 } catch (UnsupportedEncodingException encodingEx) {
3219 throw new SQLException("Unsupported character "
3220 + "encoding '" + this.encoding + "'.",
3221 SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
3222 }
3223 }
3224 }
3225 }
3226
3227 /**
3228 * Sets varying properties that depend on server information. Called once
3229 * we have connected to the server.
3230 *
3231 * @param info DOCUMENT ME!
3232 *
3233 * @throws SQLException DOCUMENT ME!
3234 */
3235 private void initializePropsFromServer(Properties info)
3236 throws SQLException {
3237 // We need to do this before any further data gets
3238 // sent to the server....
3239 boolean clientCharsetIsConfigured = configureClientCharacterSet();
3240
3241 this.useFastPing = this.io.versionMeetsMinimum(3, 22, 1);
3242
3243 this.parserKnowsUnicode = this.io.versionMeetsMinimum(4, 1, 0);
3244
3245 detectFloatingPointStyle();
3246
3247 this.serverVariables.clear();
3248
3249 //
3250 // If version is greater than 3.21.22 get the server
3251 // variables, and do configurations based on them...
3252 //
3253 if (this.io.versionMeetsMinimum(3, 21, 22)) {
3254 loadServerVariables();
3255
3256 buildCollationMapping();
3257
3258 LicenseConfiguration.checkLicenseType(this.serverVariables);
3259
3260 String lowerCaseTables = (String) serverVariables.get(
3261 "lower_case_table_names");
3262
3263 this.lowerCaseTableNames = "on".equalsIgnoreCase(lowerCaseTables)
3264 || "1".equalsIgnoreCase(lowerCaseTables)
3265 || "2".equalsIgnoreCase(lowerCaseTables);
3266
3267 configureTimezone();
3268
3269 if (this.serverVariables.containsKey("max_allowed_packet")) {
3270 this.maxAllowedPacket = Integer.parseInt((String) this.serverVariables
3271 .get("max_allowed_packet"));
3272 }
3273
3274 if (this.serverVariables.containsKey("net_buffer_length")) {
3275 this.netBufferLength = Integer.parseInt((String) this.serverVariables
3276 .get("net_buffer_length"));
3277 }
3278
3279 checkTransactionIsolationLevel();
3280
3281 //
3282 // We only do this for servers older than 4.1.0, because
3283 // 4.1.0 and newer actually send the server charset
3284 // during the handshake, and that's handled at the
3285 // top of this method...
3286 //
3287 if (!clientCharsetIsConfigured) {
3288 checkServerEncoding();
3289 }
3290
3291 this.io.checkForCharsetMismatch();
3292
3293 if (this.serverVariables.containsKey("sql_mode")) {
3294 int sqlMode = 0;
3295
3296 try {
3297 sqlMode = Integer.parseInt((String) this.serverVariables
3298 .get("sql_mode"));
3299 } catch (NumberFormatException nfe) {
3300 sqlMode = 0;
3301 }
3302
3303 if ((sqlMode & 4) > 0) {
3304 this.useAnsiQuotes = true;
3305 } else {
3306 this.useAnsiQuotes = false;
3307 }
3308 }
3309 }
3310
3311 if (this.io.versionMeetsMinimum(3, 23, 15)) {
3312 this.transactionsSupported = true;
3313 setAutoCommit(true); // to override anything
3314 // the server is set to...reqd
3315 // by JDBC spec.
3316 } else {
3317 this.transactionsSupported = false;
3318 }
3319
3320 if (this.io.versionMeetsMinimum(3, 23, 36)) {
3321 this.hasIsolationLevels = true;
3322 } else {
3323 this.hasIsolationLevels = false;
3324 }
3325
3326 // Start logging perf/profile data if the user has requested it.
3327 String profileSql = info.getProperty("profileSql");
3328
3329 if ((profileSql != null) && profileSql.trim().equalsIgnoreCase("true")) {
3330 this.io.setProfileSql(true);
3331 } else {
3332 this.io.setProfileSql(false);
3333 }
3334
3335 this.hasQuotedIdentifiers = this.io.versionMeetsMinimum(3, 23, 6);
3336
3337 // Set to what we've read from the server....
3338 this.io.resetMaxBuf();
3339
3340 //
3341 // If we're using MySQL 4.1.0 or newer, we need to figure
3342 // out what character set metadata will be returned in,
3343 // and then map that to a Java encoding name.
3344 //
3345 if (this.io.versionMeetsMinimum(4, 1, 0)) {
3346 String characterSetResultsOnServerMysql = (String)this.serverVariables.get("character_set_results");
3347
3348 if (characterSetResultsOnServerMysql == null || StringUtils.startsWithIgnoreCaseAndWs(characterSetResultsOnServerMysql, "NULL")) {
3349 String defaultMetadataCharsetMysql = (String)this.serverVariables.get("character_set_system");
3350 String defaultMetadataCharset = null;
3351
3352 if (defaultMetadataCharsetMysql != null) {
3353 defaultMetadataCharset = (String)CharsetMapping.MYSQL_TO_JAVA_CHARSET_MAP.get(defaultMetadataCharsetMysql);
3354 } else {
3355 defaultMetadataCharset = "UTF-8";
3356 }
3357
3358 this.characterSetMetadata = defaultMetadataCharset;
3359 } else {
3360 this.characterSetResultsOnServer = (String)CharsetMapping.MYSQL_TO_JAVA_CHARSET_MAP.get(characterSetResultsOnServerMysql);
3361 this.characterSetMetadata = this.characterSetResultsOnServer;
3362 }
3363 }
3364 }
3365
3366 /**
3367 * Loads the mapping between MySQL character sets and Java character sets
3368 */
3369 private static void loadCharacterSetMapping() {
3370 multibyteCharsetsMap = new HashMap();
3371
3372 Iterator multibyteCharsets = CharsetMapping.MULTIBYTE_CHARSETS.keySet()
3373 .iterator();
3374
3375 while (multibyteCharsets.hasNext()) {
3376 String charset = ((String) multibyteCharsets.next()).toUpperCase();
3377 multibyteCharsetsMap.put(charset, charset);
3378 }
3379
3380 //
3381 // Now change all server encodings to upper-case to "future-proof"
3382 // this mapping
3383 //
3384 Iterator keys = CharsetMapping.MYSQL_TO_JAVA_CHARSET_MAP.keySet()
3385 .iterator();
3386 charsetMap = new HashMap();
3387
3388 while (keys.hasNext()) {
3389 String mysqlCharsetName = ((String) keys.next()).trim();
3390 String javaCharsetName = CharsetMapping.MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlCharsetName)
3391 .toString()
3392 .trim();
3393 charsetMap.put(mysqlCharsetName.toUpperCase(), javaCharsetName);
3394 charsetMap.put(mysqlCharsetName, javaCharsetName);
3395 }
3396 }
3397
3398 private boolean getUseUltraDevWorkAround() {
3399 return useUltraDevWorkAround;
3400 }
3401
3402 /**
3403 * Loads the result of 'SHOW VARIABLES' into the serverVariables field so
3404 * that the driver can configure itself.
3405 *
3406 * @throws SQLException if the 'SHOW VARIABLES' query fails for any reason.
3407 */
3408 private void loadServerVariables() throws SQLException {
3409 com.mysql.jdbc.Statement stmt = null;
3410 com.mysql.jdbc.ResultSet results = null;
3411
3412 try {
3413 stmt = (com.mysql.jdbc.Statement) createStatement();
3414
3415 if (stmt.getMaxRows() != 0) {
3416 stmt.setMaxRows(0);
3417 }
3418
3419 results = (com.mysql.jdbc.ResultSet) stmt.executeQuery(
3420 "SHOW VARIABLES");
3421
3422 while (results.next()) {
3423 this.serverVariables.put(results.getString(1),
3424 results.getString(2));
3425 }
3426 } catch (java.sql.SQLException e) {
3427 throw e;
3428 } finally {
3429 if (results != null) {
3430 try {
3431 results.close();
3432 } catch (java.sql.SQLException sqlE) {
3433 ;
3434 }
3435 }
3436
3437 if (stmt != null) {
3438 try {
3439 stmt.close();
3440 } catch (java.sql.SQLException sqlE) {
3441 ;
3442 }
3443 }
3444 }
3445 }
3446
3447 // *********************************************************************
3448 //
3449 // END OF PUBLIC INTERFACE
3450 //
3451 // *********************************************************************
3452
3453 /**
3454 * Detect if the connection is still good
3455 *
3456 * @throws Exception DOCUMENT ME!
3457 */
3458 private void ping() throws Exception {
3459 if (this.useFastPing) {
3460 this.io.sendCommand(MysqlDefs.PING, null, null);
3461 } else {
3462 this.io.sqlQuery(PING_COMMAND, MysqlDefs.MAX_ROWS, this.encoding,
3463 this, java.sql.ResultSet.CONCUR_READ_ONLY, false, this.database);
3464 }
3465 }
3466
3467 private void pingAndReconnect(boolean ignoreAutoCommitSetting)
3468 throws SQLException {
3469 boolean localAutoCommit = this.autoCommit;
3470
3471 // We use this to catch the 'edge' case
3472 // of autoReconnect going from true->false
3473 //
3474 if (ignoreAutoCommitSetting) {
3475 localAutoCommit = true;
3476 }
3477
3478 if (this.failedOver && localAutoCommit) {
3479 this.queriesIssuedFailedOver++;
3480
3481 if (shouldFallBack()) {
3482 createNewIO(true);
3483
3484 String connectedHost = this.io.getHost();
3485
3486 if ((connectedHost != null)
3487 && this.hostList.get(0).equals(connectedHost)) {
3488 this.failedOver = false;
3489 this.queriesIssuedFailedOver = 0;
3490 setReadOnly(false);
3491 }
3492 }
3493 }
3494
3495 if ((this.highAvailability || this.failedOver) && localAutoCommit) {
3496 try {
3497 ping();
3498 } catch (Exception Ex) {
3499 createNewIO(true);
3500 }
3501 }
3502
3503 this.needsPing = false;
3504 }
3505
3506 private void rollbackNoChecks() throws SQLException {
3507 execSQL("rollback", -1, null);
3508 }
3509
3510 /**
3511 * Should we try to connect back to the master? We try when we've been
3512 * failed over >= this.secondsBeforeRetryMaster _or_ we've issued >
3513 * this.queriesIssuedFailedOver
3514 *
3515 * @return DOCUMENT ME!
3516 */
3517 private boolean shouldFallBack() {
3518 long secondsSinceFailedOver = (System.currentTimeMillis()
3519 - this.masterFailTimeMillis) / 1000;
3520
3521 return ((secondsSinceFailedOver >= this.secondsBeforeRetryMaster)
3522 || ((this.queriesIssuedFailedOver % this.queriesBeforeRetryMaster) == 0));
3523 }
3524
3525 /**
3526 * Wrapper class for UltraDev CallableStatements that are really
3527 * PreparedStatments. Nice going, UltraDev developers.
3528 */
3529 class UltraDevWorkAround implements java.sql.CallableStatement {
3530 private java.sql.PreparedStatement delegate = null;
3531
3532 UltraDevWorkAround(java.sql.PreparedStatement pstmt) {
3533 delegate = pstmt;
3534 }
3535
3536 public void setArray(int p1, final java.sql.Array p2)
3537 throws java.sql.SQLException {
3538 delegate.setArray(p1, p2);
3539 }
3540
3541 public java.sql.Array getArray(int p1) throws java.sql.SQLException {
3542 throw new SQLException("Not supported");
3543 }
3544
3545 /**
3546 * @see CallableStatement#getArray(String)
3547 */
3548 public java.sql.Array getArray(String arg0) throws SQLException {
3549 throw new NotImplemented();
3550 }
3551
3552 public void setAsciiStream(int p1, final java.io.InputStream p2, int p3)
3553 throws java.sql.SQLException {
3554 delegate.setAsciiStream(p1, p2, p3);
3555 }
3556
3557 /**
3558 * @see CallableStatement#setAsciiStream(String, InputStream, int)
3559 */
3560 public void setAsciiStream(String arg0, InputStream arg1, int arg2)
3561 throws SQLException {
3562 throw new NotImplemented();
3563 }
3564
3565 public void setBigDecimal(int p1, final java.math.BigDecimal p2)
3566 throws java.sql.SQLException {
3567 delegate.setBigDecimal(p1, p2);
3568 }
3569
3570 /**
3571 * @see CallableStatement#setBigDecimal(String, BigDecimal)
3572 */
3573 public void setBigDecimal(String arg0, BigDecimal arg1)
3574 throws SQLException {
3575 throw new NotImplemented();
3576 }
3577
3578 public java.math.BigDecimal getBigDecimal(int p1)
3579 throws java.sql.SQLException {
3580 throw new SQLException("Not supported");
3581 }
3582
3583 public java.math.BigDecimal getBigDecimal(int p1, int p2)
3584 throws java.sql.SQLException {
3585 throw new SQLException("Not supported");
3586 }
3587
3588 /**
3589 * @see CallableStatement#getBigDecimal(String)
3590 */
3591 public BigDecimal getBigDecimal(String arg0) throws SQLException {
3592 return null;
3593 }
3594
3595 public void setBinaryStream(int p1, final java.io.InputStream p2, int p3)
3596 throws java.sql.SQLException {
3597 delegate.setBinaryStream(p1, p2, p3);
3598 }
3599
3600 /**
3601 * @see CallableStatement#setBinaryStream(String, InputStream, int)
3602 */
3603 public void setBinaryStream(String arg0, InputStream arg1, int arg2)
3604 throws SQLException {
3605 throw new NotImplemented();
3606 }
3607
3608 public void setBlob(int p1, final java.sql.Blob p2)
3609 throws java.sql.SQLException {
3610 delegate.setBlob(p1, p2);
3611 }
3612
3613 public java.sql.Blob getBlob(int p1) throws java.sql.SQLException {
3614 throw new SQLException("Not supported");
3615 }
3616
3617 /**
3618 * @see CallableStatement#getBlob(String)
3619 */
3620 public java.sql.Blob getBlob(String arg0) throws SQLException {
3621 throw new NotImplemented();
3622 }
3623
3624 public void setBoolean(int p1, boolean p2) throws java.sql.SQLException {
3625 delegate.setBoolean(p1, p2);
3626 }
3627
3628 /**
3629 * @see CallableStatement#setBoolean(String, boolean)
3630 */
3631 public void setBoolean(String arg0, boolean arg1)
3632 throws SQLException {
3633 throw new NotImplemented();
3634 }
3635
3636 public boolean getBoolean(int p1) throws java.sql.SQLException {
3637 throw new SQLException("Not supported");
3638 }
3639
3640 /**
3641 * @see CallableStatement#getBoolean(String)
3642 */
3643 public boolean getBoolean(String arg0) throws SQLException {
3644 throw new NotImplemented();
3645 }
3646
3647 public void setByte(int p1, byte p2) throws java.sql.SQLException {
3648 delegate.setByte(p1, p2);
3649 }
3650
3651 /**
3652 * @see CallableStatement#setByte(String, byte)
3653 */
3654 public void setByte(String arg0, byte arg1) throws SQLException {
3655 throw new NotImplemented();
3656 }
3657
3658 public byte getByte(int p1) throws java.sql.SQLException {
3659 throw new SQLException("Not supported");
3660 }
3661
3662 /**
3663 * @see CallableStatement#getByte(String)
3664 */
3665 public byte getByte(String arg0) throws SQLException {
3666 throw new NotImplemented();
3667 }
3668
3669 public void setBytes(int p1, byte[] p2) throws java.sql.SQLException {
3670 delegate.setBytes(p1, p2);
3671 }
3672
3673 /**
3674 * @see CallableStatement#setBytes(String, byte[])
3675 */
3676 public void setBytes(String arg0, byte[] arg1)
3677 throws SQLException {
3678 throw new NotImplemented();
3679 }
3680
3681 public byte[] getBytes(int p1) throws java.sql.SQLException {
3682 throw new SQLException("Not supported");
3683 }
3684
3685 /**
3686 * @see CallableStatement#getBytes(String)
3687 */
3688 public byte[] getBytes(String arg0) throws SQLException {
3689 throw new NotImplemented();
3690 }
3691
3692 public void setCharacterStream(int p1, final java.io.Reader p2, int p3)
3693 throws java.sql.SQLException {
3694 delegate.setCharacterStream(p1, p2, p3);
3695 }
3696
3697 /**
3698 * @see CallableStatement#setCharacterStream(String, Reader, int)
3699 */
3700 public void setCharacterStream(String arg0, Reader arg1, int arg2)
3701 throws SQLException {
3702 throw new NotImplemented();
3703 }
3704
3705 public void setClob(int p1, final java.sql.Clob p2)
3706 throws java.sql.SQLException {
3707 delegate.setClob(p1, p2);
3708 }
3709
3710 public java.sql.Clob getClob(int p1) throws java.sql.SQLException {
3711 throw new SQLException("Not supported");
3712 }
3713
3714 /**
3715 * @see CallableStatement#getClob(String)
3716 */
3717 public Clob getClob(String arg0) throws SQLException {
3718 throw new NotImplemented();
3719 }
3720
3721 public java.sql.Connection getConnection() throws java.sql.SQLException {
3722 return delegate.getConnection();
3723 }
3724
3725 public void setCursorName(java.lang.String p1)
3726 throws java.sql.SQLException {
3727 throw new SQLException("Not supported");
3728 }
3729
3730 public void setDate(int p1, final java.sql.Date p2)
3731 throws java.sql.SQLException {
3732 delegate.setDate(p1, p2);
3733 }
3734
3735 public void setDate(int p1, final java.sql.Date p2,
3736 final java.util.Calendar p3) throws java.sql.SQLException {
3737 delegate.setDate(p1, p2, p3);
3738 }
3739
3740 /**
3741 * @see CallableStatement#setDate(String, Date, Calendar)
3742 */
3743 public void setDate(String arg0, Date arg1, Calendar arg2)
3744 throws SQLException {
3745 throw new NotImplemented();
3746 }
3747
3748 /**
3749 * @see CallableStatement#setDate(String, Date)
3750 */
3751 public void setDate(String arg0, Date arg1) throws SQLException {
3752 throw new NotImplemented();
3753 }
3754
3755 public java.sql.Date getDate(int p1) throws java.sql.SQLException {
3756 throw new SQLException("Not supported");
3757 }
3758
3759 public java.sql.Date getDate(int p1, final java.util.Calendar p2)
3760 throws java.sql.SQLException {
3761 throw new SQLException("Not supported");
3762 }
3763
3764 /**
3765 * @see CallableStatement#getDate(String, Calendar)
3766 */
3767 public Date getDate(String arg0, Calendar arg1)
3768 throws SQLException {
3769 throw new NotImplemented();
3770 }
3771
3772 /**
3773 * @see CallableStatement#getDate(String)
3774 */
3775 public Date getDate(String arg0) throws SQLException {
3776 throw new NotImplemented();
3777 }
3778
3779 public void setDouble(int p1, double p2) throws java.sql.SQLException {
3780 delegate.setDouble(p1, p2);
3781 }
3782
3783 /**
3784 * @see CallableStatement#setDouble(String, double)
3785 */
3786 public void setDouble(String arg0, double arg1)
3787 throws SQLException {
3788 throw new NotImplemented();
3789 }
3790
3791 public double getDouble(int p1) throws java.sql.SQLException {
3792 throw new SQLException("Not supported");
3793 }
3794
3795 /**
3796 * @see CallableStatement#getDouble(String)
3797 */
3798 public double getDouble(String arg0) throws SQLException {
3799 throw new NotImplemented();
3800 }
3801
3802 public void setEscapeProcessing(boolean p1)
3803 throws java.sql.SQLException {
3804 delegate.setEscapeProcessing(p1);
3805 }
3806
3807 public void setFetchDirection(int p1) throws java.sql.SQLException {
3808 delegate.setFetchDirection(p1);
3809 }
3810
3811 public int getFetchDirection() throws java.sql.SQLException {
3812 return delegate.getFetchDirection();
3813 }
3814
3815 public void setFetchSize(int p1) throws java.sql.SQLException {
3816 delegate.setFetchSize(p1);
3817 }
3818
3819 public int getFetchSize() throws java.sql.SQLException {
3820 return delegate.getFetchSize();
3821 }
3822
3823 public void setFloat(int p1, float p2) throws java.sql.SQLException {
3824 delegate.setFloat(p1, p2);
3825 }
3826
3827 /**
3828 * @see CallableStatement#setFloat(String, float)
3829 */
3830 public void setFloat(String arg0, float arg1) throws SQLException {
3831 throw new NotImplemented();
3832 }
3833
3834 public float getFloat(int p1) throws java.sql.SQLException {
3835 throw new SQLException("Not supported");
3836 }
3837
3838 /**
3839 * @see CallableStatement#getFloat(String)
3840 */
3841 public float getFloat(String arg0) throws SQLException {
3842 throw new NotImplemented();
3843 }
3844
3845 /**
3846 * @see Statement#getGeneratedKeys()
3847 */
3848 public java.sql.ResultSet getGeneratedKeys() throws SQLException {
3849 return delegate.getGeneratedKeys();
3850 }
3851
3852 public void setInt(int p1, int p2) throws java.sql.SQLException {
3853 delegate.setInt(p1, p2);
3854 }
3855
3856 /**
3857 * @see CallableStatement#setInt(String, int)
3858 */
3859 public void setInt(String arg0, int arg1) throws SQLException {
3860 throw new NotImplemented();
3861 }
3862
3863 public int getInt(int p1) throws java.sql.SQLException {
3864 throw new SQLException("Not supported");
3865 }
3866
3867 /**
3868 * @see CallableStatement#getInt(String)
3869 */
3870 public int getInt(String arg0) throws SQLException {
3871 throw new NotImplemented();
3872 }
3873
3874 public void setLong(int p1, long p2) throws java.sql.SQLException {
3875 delegate.setLong(p1, p2);
3876 }
3877
3878 /**
3879 * @see CallableStatement#setLong(String, long)
3880 */
3881 public void setLong(String arg0, long arg1) throws SQLException {
3882 throw new NotImplemented();
3883 }
3884
3885 public long getLong(int p1) throws java.sql.SQLException {
3886 throw new SQLException("Not supported");
3887 }
3888
3889 /**
3890 * @see CallableStatement#getLong(String)
3891 */
3892 public long getLong(String arg0) throws SQLException {
3893 throw new NotImplemented();
3894 }
3895
3896 public void setMaxFieldSize(int p1) throws java.sql.SQLException {
3897 delegate.setMaxFieldSize(p1);
3898 }
3899
3900 public int getMaxFieldSize() throws java.sql.SQLException {
3901 return delegate.getMaxFieldSize();
3902 }
3903
3904 public void setMaxRows(int p1) throws java.sql.SQLException {
3905 delegate.setMaxRows(p1);
3906 }
3907
3908 public int getMaxRows() throws java.sql.SQLException {
3909 return delegate.getMaxRows();
3910 }
3911
3912 public java.sql.ResultSetMetaData getMetaData()
3913 throws java.sql.SQLException {
3914 throw new SQLException("Not supported");
3915 }
3916
3917 public boolean getMoreResults() throws java.sql.SQLException {
3918 return delegate.getMoreResults();
3919 }
3920
3921 /**
3922 * @see Statement#getMoreResults(int)
3923 */
3924 public boolean getMoreResults(int arg0) throws SQLException {
3925 return delegate.getMoreResults();
3926 }
3927
3928 public void setNull(int p1, int p2) throws java.sql.SQLException {
3929 delegate.setNull(p1, p2);
3930 }
3931
3932 public void setNull(int p1, int p2, java.lang.String p3)
3933 throws java.sql.SQLException {
3934 delegate.setNull(p1, p2, p3);
3935 }
3936
3937 /**
3938 * @see CallableStatement#setNull(String, int, String)
3939 */
3940 public void setNull(String arg0, int arg1, String arg2)
3941 throws SQLException {
3942 throw new NotImplemented();
3943 }
3944
3945 /**
3946 * @see CallableStatement#setNull(String, int)
3947 */
3948 public void setNull(String arg0, int arg1) throws SQLException {
3949 throw new NotImplemented();
3950 }
3951
3952 public void setObject(int p1, final java.lang.Object p2)
3953 throws java.sql.SQLException {
3954 delegate.setObject(p1, p2);
3955 }
3956
3957 public void setObject(int p1, final java.lang.Object p2, int p3)
3958 throws java.sql.SQLException {
3959 delegate.setObject(p1, p2, p3);
3960 }
3961
3962 public void setObject(int p1, final java.lang.Object p2, int p3, int p4)
3963 throws java.sql.SQLException {
3964 delegate.setObject(p1, p2, p3, p4);
3965 }
3966
3967 /**
3968 * @see CallableStatement#setObject(String, Object, int, int)
3969 */
3970 public void setObject(String arg0, Object arg1, int arg2, int arg3)
3971 throws SQLException {
3972 throw new NotImplemented();
3973 }
3974
3975 /**
3976 * @see CallableStatement#setObject(String, Object, int)
3977 */
3978 public void setObject(String arg0, Object arg1, int arg2)
3979 throws SQLException {
3980 throw new NotImplemented();
3981 }
3982
3983 /**
3984 * @see CallableStatement#setObject(String, Object)
3985 */
3986 public void setObject(String arg0, Object arg1)
3987 throws SQLException {
3988 throw new NotImplemented();
3989 }
3990
3991 public java.lang.Object getObject(int p1) throws java.sql.SQLException {
3992 throw new SQLException("Not supported");
3993 }
3994
3995 public java.lang.Object getObject(int p1, final java.util.Map p2)
3996 throws java.sql.SQLException {
3997 throw new SQLException("Not supported");
3998 }
3999
4000 /**
4001 * @see CallableStatement#getObject(String, Map)
4002 */
4003 public Object getObject(String arg0, Map arg1)
4004 throws SQLException {
4005 throw new NotImplemented();
4006 }
4007
4008 /**
4009 * @see CallableStatement#getObject(String)
4010 */
4011 public Object getObject(String arg0) throws SQLException {
4012 throw new NotImplemented();
4013 }
4014
4015 /**
4016 * @see PreparedStatement#getParameterMetaData()
4017 */
4018 public ParameterMetaData getParameterMetaData()
4019 throws SQLException {
4020 return delegate.getParameterMetaData();
4021 }
4022
4023 public void setQueryTimeout(int p1) throws java.sql.SQLException {
4024 throw new SQLException("Not supported");
4025 }
4026
4027 public int getQueryTimeout() throws java.sql.SQLException {
4028 return delegate.getQueryTimeout();
4029 }
4030
4031 public void setRef(int p1, final java.sql.Ref p2)
4032 throws java.sql.SQLException {
4033 throw new SQLException("Not supported");
4034 }
4035
4036 public java.sql.Ref getRef(int p1) throws java.sql.SQLException {
4037 throw new SQLException("Not supported");
4038 }
4039
4040 /**
4041 * @see CallableStatement#getRef(String)
4042 */
4043 public Ref getRef(String arg0) throws SQLException {
4044 throw new NotImplemented();
4045 }
4046
4047 public java.sql.ResultSet getResultSet() throws java.sql.SQLException {
4048 return delegate.getResultSet();
4049 }
4050
4051 public int getResultSetConcurrency() throws java.sql.SQLException {
4052 return delegate.getResultSetConcurrency();
4053 }
4054
4055 /**
4056 * @see Statement#getResultSetHoldability()
4057 */
4058 public int getResultSetHoldability() throws SQLException {
4059 return delegate.getResultSetHoldability();
4060 }
4061
4062 public int getResultSetType() throws java.sql.SQLException {
4063 return delegate.getResultSetType();
4064 }
4065
4066 public void setShort(int p1, short p2) throws java.sql.SQLException {
4067 delegate.setShort(p1, p2);
4068 }
4069
4070 /**
4071 * @see CallableStatement#setShort(String, short)
4072 */
4073 public void setShort(String arg0, short arg1) throws SQLException {
4074 throw new NotImplemented();
4075 }
4076
4077 public short getShort(int p1) throws java.sql.SQLException {
4078 throw new SQLException("Not supported");
4079 }
4080
4081 /**
4082 * @see CallableStatement#getShort(String)
4083 */
4084 public short getShort(String arg0) throws SQLException {
4085 throw new NotImplemented();
4086 }
4087
4088 public void setString(int p1, java.lang.String p2)
4089 throws java.sql.SQLException {
4090 delegate.setString(p1, p2);
4091 }
4092
4093 /**
4094 * @see CallableStatement#setString(String, String)
4095 */
4096 public void setString(String arg0, String arg1)
4097 throws SQLException {
4098 throw new NotImplemented();
4099 }
4100
4101 public java.lang.String getString(int p1) throws java.sql.SQLException {
4102 throw new SQLException("Not supported");
4103 }
4104
4105 /**
4106 * @see CallableStatement#getString(String)
4107 */
4108 public String getString(String arg0) throws SQLException {
4109 throw new NotImplemented();
4110 }
4111
4112 public void setTime(int p1, final java.sql.Time p2)
4113 throws java.sql.SQLException {
4114 delegate.setTime(p1, p2);
4115 }
4116
4117 public void setTime(int p1, final java.sql.Time p2,
4118 final java.util.Calendar p3) throws java.sql.SQLException {
4119 delegate.setTime(p1, p2, p3);
4120 }
4121
4122 /**
4123 * @see CallableStatement#setTime(String, Time, Calendar)
4124 */
4125 public void setTime(String arg0, Time arg1, Calendar arg2)
4126 throws SQLException {
4127 throw new NotImplemented();
4128 }
4129
4130 /**
4131 * @see CallableStatement#setTime(String, Time)
4132 */
4133 public void setTime(String arg0, Time arg1) throws SQLException {
4134 throw new NotImplemented();
4135 }
4136
4137 public java.sql.Time getTime(int p1) throws java.sql.SQLException {
4138 throw new SQLException("Not supported");
4139 }
4140
4141 public java.sql.Time getTime(int p1, final java.util.Calendar p2)
4142 throws java.sql.SQLException {
4143 throw new SQLException("Not supported");
4144 }
4145
4146 /**
4147 * @see CallableStatement#getTime(String, Calendar)
4148 */
4149 public Time getTime(String arg0, Calendar arg1)
4150 throws SQLException {
4151 throw new NotImplemented();
4152 }
4153
4154 /**
4155 * @see CallableStatement#getTime(String)
4156 */
4157 public Time getTime(String arg0) throws SQLException {
4158 throw new NotImplemented();
4159 }
4160
4161 public void setTimestamp(int p1, final java.sql.Timestamp p2)
4162 throws java.sql.SQLException {
4163 delegate.setTimestamp(p1, p2);
4164 }
4165
4166 public void setTimestamp(int p1, final java.sql.Timestamp p2,
4167 final java.util.Calendar p3) throws java.sql.SQLException {
4168 delegate.setTimestamp(p1, p2, p3);
4169 }
4170
4171 /**
4172 * @see CallableStatement#setTimestamp(String, Timestamp, Calendar)
4173 */
4174 public void setTimestamp(String arg0, Timestamp arg1, Calendar arg2)
4175 throws SQLException {
4176 throw new NotImplemented();
4177 }
4178
4179 /**
4180 * @see CallableStatement#setTimestamp(String, Timestamp)
4181 */
4182 public void setTimestamp(String arg0, Timestamp arg1)
4183 throws SQLException {
4184 throw new NotImplemented();
4185 }
4186
4187 public java.sql.Timestamp getTimestamp(int p1)
4188 throws java.sql.SQLException {
4189 throw new SQLException("Not supported");
4190 }
4191
4192 public java.sql.Timestamp getTimestamp(int p1,
4193 final java.util.Calendar p2) throws java.sql.SQLException {
4194 throw new SQLException("Not supported");
4195 }
4196
4197 /**
4198 * @see CallableStatement#getTimestamp(String, Calendar)
4199 */
4200 public Timestamp getTimestamp(String arg0, Calendar arg1)
4201 throws SQLException {
4202 throw new NotImplemented();
4203 }
4204
4205 /**
4206 * @see CallableStatement#getTimestamp(String)
4207 */
4208 public Timestamp getTimestamp(String arg0) throws SQLException {
4209 throw new NotImplemented();
4210 }
4211
4212 /**
4213 * @see CallableStatement#setURL(String, URL)
4214 */
4215 public void setURL(String arg0, URL arg1) throws SQLException {
4216 throw new NotImplemented();
4217 }
4218
4219 /**
4220 * @see PreparedStatement#setURL(int, URL)
4221 */
4222 public void setURL(int arg0, URL arg1) throws SQLException {
4223 delegate.setURL(arg0, arg1);
4224 }
4225
4226 /**
4227 * @see CallableStatement#getURL(int)
4228 */
4229 public URL getURL(int arg0) throws SQLException {
4230 throw new NotImplemented();
4231 }
4232
4233 /**
4234 * @see CallableStatement#getURL(String)
4235 */
4236 public URL getURL(String arg0) throws SQLException {
4237 throw new NotImplemented();
4238 }
4239
4240 /**
4241 * @deprecated -- we know, but we need to override...
4242 */
4243 public void setUnicodeStream(int p1, final java.io.InputStream p2,
4244 int p3) throws java.sql.SQLException {
4245 delegate.setUnicodeStream(p1, p2, p3);
4246 }
4247
4248 public int getUpdateCount() throws java.sql.SQLException {
4249 return delegate.getUpdateCount();
4250 }
4251
4252 public java.sql.SQLWarning getWarnings() throws java.sql.SQLException {
4253 return delegate.getWarnings();
4254 }
4255
4256 public void addBatch() throws java.sql.SQLException {
4257 delegate.addBatch();
4258 }
4259
4260 public void addBatch(java.lang.String p1) throws java.sql.SQLException {
4261 delegate.addBatch(p1);
4262 }
4263
4264 public void cancel() throws java.sql.SQLException {
4265 delegate.cancel();
4266 }
4267
4268 public void clearBatch() throws java.sql.SQLException {
4269 delegate.clearBatch();
4270 }
4271
4272 public void clearParameters() throws java.sql.SQLException {
4273 delegate.clearParameters();
4274 }
4275
4276 public void clearWarnings() throws java.sql.SQLException {
4277 delegate.clearWarnings();
4278 }
4279
4280 public void close() throws java.sql.SQLException {
4281 delegate.close();
4282 }
4283
4284 public boolean execute() throws java.sql.SQLException {
4285 return delegate.execute();
4286 }
4287
4288 public boolean execute(java.lang.String p1)
4289 throws java.sql.SQLException {
4290 return delegate.execute(p1);
4291 }
4292
4293 /**
4294 * @see Statement#execute(String, int)
4295 */
4296 public boolean execute(String arg0, int arg1) throws SQLException {
4297 return delegate.execute(arg0, arg1);
4298 }
4299
4300 /**
4301 * @see Statement#execute(String, int[])
4302 */
4303 public boolean execute(String arg0, int[] arg1)
4304 throws SQLException {
4305 return delegate.execute(arg0, arg1);
4306 }
4307
4308 /**
4309 * @see Statement#execute(String, String[])
4310 */
4311 public boolean execute(String arg0, String[] arg1)
4312 throws SQLException {
4313 return delegate.execute(arg0, arg1);
4314 }
4315
4316 public int[] executeBatch() throws java.sql.SQLException {
4317 return delegate.executeBatch();
4318 }
4319
4320 public java.sql.ResultSet executeQuery() throws java.sql.SQLException {
4321 return delegate.executeQuery();
4322 }
4323
4324 public java.sql.ResultSet executeQuery(java.lang.String p1)
4325 throws java.sql.SQLException {
4326 return delegate.executeQuery(p1);
4327 }
4328
4329 public int executeUpdate() throws java.sql.SQLException {
4330 return delegate.executeUpdate();
4331 }
4332
4333 public int executeUpdate(java.lang.String p1)
4334 throws java.sql.SQLException {
4335 return delegate.executeUpdate(p1);
4336 }
4337
4338 /**
4339 * @see Statement#executeUpdate(String, int)
4340 */
4341 public int executeUpdate(String arg0, int arg1)
4342 throws SQLException {
4343 return delegate.executeUpdate(arg0, arg1);
4344 }
4345
4346 /**
4347 * @see Statement#executeUpdate(String, int[])
4348 */
4349 public int executeUpdate(String arg0, int[] arg1)
4350 throws SQLException {
4351 return delegate.executeUpdate(arg0, arg1);
4352 }
4353
4354 /**
4355 * @see Statement#executeUpdate(String, String[])
4356 */
4357 public int executeUpdate(String arg0, String[] arg1)
4358 throws SQLException {
4359 return delegate.executeUpdate(arg0, arg1);
4360 }
4361
4362 public void registerOutParameter(int p1, int p2)
4363 throws java.sql.SQLException {
4364 throw new SQLException("Not supported");
4365 }
4366
4367 public void registerOutParameter(int p1, int p2, int p3)
4368 throws java.sql.SQLException {
4369 throw new SQLException("Not supported");
4370 }
4371
4372 public void registerOutParameter(int p1, int p2, java.lang.String p3)
4373 throws java.sql.SQLException {
4374 throw new SQLException("Not supported");
4375 }
4376
4377 /**
4378 * @see CallableStatement#registerOutParameter(String, int, int)
4379 */
4380 public void registerOutParameter(String arg0, int arg1, int arg2)
4381 throws SQLException {
4382 throw new NotImplemented();
4383 }
4384
4385 /**
4386 * @see CallableStatement#registerOutParameter(String, int, String)
4387 */
4388 public void registerOutParameter(String arg0, int arg1, String arg2)
4389 throws SQLException {
4390 throw new NotImplemented();
4391 }
4392
4393 /**
4394 * @see CallableStatement#registerOutParameter(String, int)
4395 */
4396 public void registerOutParameter(String arg0, int arg1)
4397 throws SQLException {
4398 throw new NotImplemented();
4399 }
4400
4401 public boolean wasNull() throws java.sql.SQLException {
4402 throw new SQLException("Not supported");
4403 }
4404 }
4405
4406 /**
4407 * @return Returns the characterSetMetadata.
4408 */
4409 protected String getCharacterSetMetadata() {
4410 return characterSetMetadata;
4411 }
4412
4413 /**
4414 * Returns the server's character set
4415 *
4416 * @return the server's character set.
4417 */
4418 protected String getServerCharacterEncoding() {
4419 return (String)this.serverVariables.get("character_set");
4420 }
4421
4422 /**
4423 * @return Returns the rollbackOnPooledClose.
4424 */
4425 public boolean getRollbackOnPooledClose() {
4426 return rollbackOnPooledClose;
4427 }
4428 /**
4429 * @return Returns the useOnlyServerErrorMessages.
4430 */
4431 protected boolean getUseOnlyServerErrorMessages() {
4432 return this.useOnlyServerErrorMessages;
4433 }
4434
4435 /**
4436 * @return
4437 */
4438 public boolean getTinyint1isBit() {
4439 // TODO Auto-generated method stub
4440 return this.tinyint1isBit;
4441 }
4442}