|
What this is
Other links
The source code
/*
* MM JDBC Drivers for MySQL
*
* $Id: Connection.java,v 1.2 1998/08/25 00:53:46 mmatthew Exp $
*
* Copyright (C) 1998 Mark Matthews <mmatthew@worldserver.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* See the COPYING file located in the top-level-directory of
* the archive of this library for complete text of license.
*
* Some portions:
*
* Copyright (c) 1996 Bradley McLean / Jeffrey Medeiros
* Modifications Copyright (c) 1996/1997 Martin Rode
* Copyright (c) 1997 Peter T Mount
*/
/**
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
* returned.
*
* <P>A Connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is obtained
* with the getMetaData method.
*
* <p>Note: MySQL does not support transactions, so all queries
* are committed as they are executed.
*
* @see java.sql.Connection
* @author Mark Matthews <mmatthew@worldserver.com>
* @version $Id$
*/
package org.gjt.mm.mysql;
import java.io.UnsupportedEncodingException;
import java.sql.*;
import java.util.Properties;
public class Connection implements java.sql.Connection
{
MysqlIO _IO = null;
private boolean _isClosed = true;
private String _Host = null;
private int _port = 3306;
private String _User = null;
private String _Password = null;
private String _Database = null;
private boolean _autoCommit = true;
private boolean _readOnly = false;
private boolean _do_unicode = false;
private String _Encoding = null;
private String _MyURL = null;
private int _max_rows = -1;
private boolean _max_rows_changed = false;
private org.gjt.mm.mysql.Driver _MyDriver;
//
// This is for the high availability :) routines
//
private boolean _high_availability = false;
private int _max_reconnects = 3;
private double _initial_timeout = 2.0D;
// The command used to "ping" the database.
// Newer versions of MySQL server have a ping() command,
// but this works for everything.
private static final String _PING_COMMAND = "SELECT 1";
/**
* Connect to a MySQL Server.
*
* <p>Important Notice
*
* <br>Although this will connect to the database, user code should open
* the connection via the DriverManager.getConnection() methods only.
*
* <br>This should only be called from the org.gjt.mm.mysql.Driver class.
*
* @param Host the hostname of the database server
* @param port the port number the server is listening on
* @param Info a Properties[] list holding the user and password
* @param Database the database to connect to
* @param Url the URL of the connection
* @param D the Driver instantation of the connection
* @return a valid connection profile
* @exception java.sql.SQLException if a database access error occurs
*/
public Connection(String Host, int port, Properties Info, String Database,
String Url, Driver D) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {Host, new Integer(port), Info,
Database, Url, D};
Debug.methodCall(this, "constructor", Args);
}
if (Host == null) {
_Host = "localhost";
}
else {
_Host = new String(Host);
}
_port = port;
if (Database == null) {
throw new SQLException("Malformed URL '" + Url + "'.", "S1000");
}
_Database = new String(Database);
_MyURL = new String(Url);
_MyDriver = D;
String U = Info.getProperty("user");
String P = Info.getProperty("password");
if (U == null || U.equals(""))
_User = "nobody";
else
_User = new String(U);
if (P == null)
_Password = "";
else
_Password = new String(P);
// Check for driver specific properties
if (Info.getProperty("autoReconnect") != null) {
_high_availability = Info.getProperty("autoReconnect").toUpperCase().equals("TRUE");
}
if (_high_availability) {
if (Info.getProperty("maxReconnects") != null) {
try {
int n = Integer.parseInt(Info.getProperty("maxReconnects"));
_max_reconnects = n;
}
catch (NumberFormatException NFE) {
throw new SQLException("Illegal parameter '" +
Info.getProperty("maxReconnects")
+"' for maxReconnects", "0S100");
}
}
if (Info.getProperty("initialTimeout") != null) {
try {
double n = Integer.parseInt(Info.getProperty("intialTimeout"));
_initial_timeout = n;
}
catch (NumberFormatException NFE) {
throw new SQLException("Illegal parameter '" +
Info.getProperty("initialTimeout")
+"' for initialTimeout", "0S100");
}
}
}
if (Info.getProperty("maxRows") != null) {
try {
int n = Integer.parseInt(Info.getProperty("maxRows"));
if (n == 0) {
n = -1;
} // adjust so that it will become MysqlDefs.MAX_ROWS
// in execSQL()
_max_rows = n;
}
catch (NumberFormatException NFE) {
throw new SQLException("Illegal parameter '" +
Info.getProperty("maxRows")
+"' for maxRows", "0S100");
}
}
if (Info.getProperty("useUnicode") != null) {
String UseUnicode = Info.getProperty("useUnicode").toUpperCase();
if (UseUnicode.startsWith("TRUE")) {
_do_unicode = true;
}
if (Info.getProperty("characterEncoding") != null) {
_Encoding = Info.getProperty("characterEncoding");
// Attempt to use the encoding, and bail out if it
// can't be used
try {
String TestString = "abc";
TestString.getBytes(_Encoding);
}
catch (UnsupportedEncodingException UE) {
throw new SQLException("Unsupported character encoding '" +
_Encoding + "'.", "0S100");
}
}
}
if (Driver.debug)
System.out.println("Connect: " + _User + " to " + _Database);
try {
_IO = new MysqlIO(Host, port);
_IO.init(_User, _Password);
_IO.sendCommand(MysqlDefs.INIT_DB, _Database, null);
_isClosed = false;
}
catch (java.sql.SQLException E) {
throw E;
}
catch (Exception E) {
E.printStackTrace();
throw new java.sql.SQLException("Cannot connect to MySQL server on " + _Host + ":" + _port + ". Is there a MySQL server running on the machine/port you are trying to connect to? (" + E.getClass().getName() + ")", "08S01");
}
}
/**
* SQL statements without parameters are normally executed using
* Statement objects. If the same SQL statement is executed many
* times, it is more efficient to use a PreparedStatement
*
* @return a new Statement object
* @exception java.sql.SQLException passed through from the constructor
*/
public java.sql.Statement createStatement() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "createStatement", Args);
}
if (Driver.debug) {
System.out.println(this + " creating statement.");
}
org.gjt.mm.mysql.Statement Stmt = new org.gjt.mm.mysql.Statement(this, _Database);
if (_max_rows != -1) {
Stmt.setMaxRows(_max_rows);
}
if (Driver.trace) {
Debug.returnValue(this, "createStatement", Stmt);
}
return Stmt;
}
/**
* A SQL statement with or without IN parameters can be pre-compiled
* and stored in a PreparedStatement object. This object can then
* be used to efficiently execute this statement multiple times.
*
* <p>
* <B>Note: This method is optimized for handling parametric
* SQL statements that benefit from precompilation if the driver
* supports precompilation.
* In this case, the statement is not sent to the database until the
* PreparedStatement is executed. This has no direct effect on users;
* however it does affect which method throws certain java.sql.SQLExceptions
*
* <p>
* MySQL does not support precompilation of statements, so they
* are handled by the driver.
*
* @param sql a SQL statement that may contain one or more '?' IN
* parameter placeholders
* @return a new PreparedStatement object containing the pre-compiled
* statement.
* @exception java.sql.SQLException if a database access error occurs.
*/
public java.sql.PreparedStatement prepareStatement(String Sql) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {Sql};
Debug.methodCall(this, "prepareStatement", Args);
}
PreparedStatement PStmt = new org.gjt.mm.mysql.PreparedStatement(this, Sql, _Database);
if (Driver.trace) {
Debug.returnValue(this, "prepareStatement", PStmt);
}
return PStmt;
}
/**
* A SQL stored procedure call statement is handled by creating a
* CallableStatement for it. The CallableStatement provides methods
* for setting up its IN and OUT parameters and methods for executing
* it.
*
* <B>Note: This method is optimised for handling stored procedure
* call statements. Some drivers may send the call statement to the
* database when the prepareCall is done; others may wait until the
* CallableStatement is executed. This has no direct effect on users;
* however, it does affect which method throws certain java.sql.SQLExceptions
*
* @param sql a SQL statement that may contain one or more '?' parameter
* placeholders. Typically this statement is a JDBC function call
* escape string.
* @return a new CallableStatement object containing the pre-compiled
* SQL statement
* @exception java.sql.SQLException if a database access error occurs
*/
public java.sql.CallableStatement prepareCall(String Sql) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {Sql};
Debug.methodCall(this, "prepareCall", Args);
}
throw new java.sql.SQLException("Callable statments not suppoted.", "S1C00");
}
/**
* A driver may convert the JDBC sql grammar into its system's
* native SQL grammar prior to sending it; nativeSQL returns the
* native form of the statement that the driver would have sent.
*
* @param sql a SQL statement that may contain one or more '?'
* parameter placeholders
* @return the native form of this statement
* @exception java.sql.SQLException if a database access error occurs
*/
public String nativeSQL(String Sql) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {Sql};
Debug.methodCall(this, "nativeSQL", Args);
Debug.returnValue(this, "nativeSQL", Sql);
}
return Sql;
}
/**
* If a connection is in auto-commit mode, than all its SQL
* statements will be executed and committed as individual
* transactions. Otherwise, its SQL statements are grouped
* into transactions that are terminated by either commit()
* or rollback(). By default, new connections are in auto-
* commit mode. The commit occurs when the statement completes
* or the next execute occurs, whichever comes first. In the
* case of statements returning a ResultSet, the statement
* completes when the last row of the ResultSet has been retrieved
* or the ResultSet has been closed. In advanced cases, a single
* statement may return multiple results as well as output parameter
* values. Here the commit occurs when all results and output param
* values have been retrieved.
*
* <p>Note: MySQL does not support transactions, so this
* method is a no-op.
*
* @param autoCommit - true enables auto-commit; false disables it
* @exception java.sql.SQLException if a database access error occurs
*/
public void setAutoCommit(boolean autoCommit) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {new Boolean(autoCommit)};
Debug.methodCall(this, "setAutoCommit", Args);
}
if (autoCommit == false) {
throw new SQLException("Cannot disable AUTO_COMMIT", "08003");
}
return;
}
/**
* gets the current auto-commit state
*
* @return Current state of the auto-commit mode
* @exception java.sql.SQLException (why?)
* @see setAutoCommit
*/
public boolean getAutoCommit() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "getAutoCommit", Args);
Debug.returnValue(this, "getAutoCommit", new Boolean(_autoCommit));
}
return _autoCommit;
}
/**
* The method commit() makes all changes made since the previous
* commit/rollback permanent and releases any database locks currently
* held by the Connection. This method should only be used when
* auto-commit has been disabled. (If autoCommit == true, then we
* just return anyhow)
*
* <p>Note: MySQL does not support transactions, so this
* method is a no-op.
*
* @exception java.sql.SQLException if a database access error occurs
* @see setAutoCommit
*/
public void commit() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "commit", Args);
}
return;
}
/**
* The method rollback() drops all changes made since the previous
* commit/rollback and releases any database locks currently held by
* the Connection.
*
* <p>Note: MySQL does not support transactions, so this
* method is a no-op.
*
* @exception java.sql.SQLException if a database access error occurs
* @see commit
*/
public void rollback() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "rollback", Args);
}
if (_isClosed) {
throw new java.sql.SQLException("Rollback attempt on closed connection.", "08003");
}
}
/**
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head)
*
* <B>Note: A Connection is automatically closed when it is
* garbage collected. Certain fatal errors also result in a closed
* connection.
*
* @exception java.sql.SQLException if a database access error occurs
*/
public void close() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "close", Args);
}
if (_IO != null)
{
try {
_IO.quit();
}
catch (Exception e) {}
_IO = null;
}
_isClosed = true;
}
/**
* Tests to see if a Connection is closed
*
* @return the status of the connection
* @exception java.sql.SQLException (why?)
*/
public boolean isClosed() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "isClosed", Args);
Debug.returnValue(this, "isClosed", new Boolean(_isClosed));
}
if (!_isClosed) {
// Test the connection
try {
synchronized (_IO) {
execSQL(_PING_COMMAND, -1);
}
}
catch (Exception E) {
_isClosed = true;
}
}
return _isClosed;
}
/**
* A connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is made
* available through a DatabaseMetaData object.
*
* @return a DatabaseMetaData object for this connection
* @exception java.sql.SQLException if a database access error occurs
*/
public java.sql.DatabaseMetaData getMetaData() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "getMetaData", Args);
}
org.gjt.mm.mysql.DatabaseMetaData DBMD =
new org.gjt.mm.mysql.DatabaseMetaData(this, _Database);
if (Driver.trace) {
Debug.returnValue(this, "getMetaData", DBMD);
}
return DBMD;
}
/**
* You can put a connection in read-only mode as a hint to enable
* database optimizations
*
* <B>Note: setReadOnly cannot be called while in the middle
* of a transaction
*
* @param readOnly - true enables read-only mode; false disables it
* @exception java.sql.SQLException if a database access error occurs
*/
public void setReadOnly (boolean readOnly) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {new Boolean(readOnly)};
Debug.methodCall(this, "setReadOnly", Args);
Debug.returnValue(this, "setReadOnly", new Boolean(readOnly));
}
_readOnly = readOnly;
}
/**
* Tests to see if the connection is in Read Only Mode. Note that
* we cannot really put the database in read only mode, but we pretend
* we can by returning the value of the readOnly flag
*
* @return true if the connection is read only
* @exception java.sql.SQLException if a database access error occurs
*/
public boolean isReadOnly() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "isReadOnly", Args);
Debug.returnValue(this, "isReadOnly", new Boolean(_readOnly));
}
return _readOnly;
}
/**
* A sub-space of this Connection's database may be selected by
* setting a catalog name. If the driver does not support catalogs,
* it will silently ignore this request
*
* <p>Note: MySQL's notion of catalogs are individual databases.
*
* @exception java.sql.SQLException if a database access error occurs
*/
public void setCatalog(String Catalog) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {Catalog};
Debug.methodCall(this, "setCatalog", Args);
}
execSQL("USE " + Catalog, -1);
_Database = Catalog;
}
/**
* Return the connections current catalog name, or null if no
* catalog name is set, or we dont support catalogs.
*
* <p>Note: MySQL's notion of catalogs are individual databases.
* @return the current catalog name or null
* @exception java.sql.SQLException if a database access error occurs
*/
public String getCatalog() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "getCatalog", Args);
Debug.returnValue(this, "getCatalog", _Database);
}
return _Database;
}
/**
* You can call this method to try to change the transaction
* isolation level using one of the TRANSACTION_* values.
*
* <B>Note: setTransactionIsolation cannot be called while
* in the middle of a transaction
*
* @param level one of the TRANSACTION_* isolation values with
* the exception of TRANSACTION_NONE; some databases may
* not support other values
* @exception java.sql.SQLException if a database access error occurs
* @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
*/
public void setTransactionIsolation(int level) throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = {new Integer(level)};
Debug.methodCall(this, "setTransactionIsolation", Args);
}
throw new java.sql.SQLException("Transaction Isolation Levels are not supported.", "S1C00");
}
/**
* Get this Connection's current transaction isolation mode.
*
* @return the current TRANSACTION_* mode value
* @exception java.sql.SQLException if a database access error occurs
*/
public int getTransactionIsolation() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "getTransactionIsolation", Args);
Debug.returnValue(this, "getTransactionIsolation", new Integer(java.sql.Connection.TRANSACTION_SERIALIZABLE));
}
return java.sql.Connection.TRANSACTION_SERIALIZABLE;
}
/**
* The first warning reported by calls on this Connection is
* returned.
*
* <B>Note: Sebsequent warnings will be changed to this
* java.sql.SQLWarning
*
* @return the first java.sql.SQLWarning or null
* @exception java.sql.SQLException if a database access error occurs
*/
public java.sql.SQLWarning getWarnings() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "getWarnings", Args);
Debug.returnValue(this, "getWarnings", null);
}
return null;
}
/**
* After this call, getWarnings returns null until a new warning
* is reported for this connection.
*
* @exception java.sql.SQLException if a database access error occurs
*/
public void clearWarnings() throws java.sql.SQLException
{
if (Driver.trace) {
Object[] Args = new Object[0];
Debug.methodCall(this, "clearWarnings", Args);
}
// firstWarning = null;
}
// *********************************************************************
//
// END OF PUBLIC INTERFACE
//
// *********************************************************************
/**
* Send a query to the server. Returns one of the ResultSet
* objects.
*
* This is synchronized, so Statement's queries
* will be serialized.
*
* @param sql the SQL statement to be executed
* @return a ResultSet holding the results
* @exception java.sql.SQLException if a database error occurs
*/
ResultSet execSQL(String Sql, int max_rows)
throws java.sql.SQLException
{
return execSQL(Sql, max_rows, null);
}
ResultSet execSQL(String Sql, int max_rows, Buffer Packet)
throws java.sql.SQLException
{
synchronized (_IO) {
if (_high_availability) {
try {
_IO.sqlQuery(_PING_COMMAND, MysqlDefs.MAX_ROWS);
}
catch (Exception Ex) {
double timeout = _initial_timeout;
boolean connection_good = false;
for (int i = 0; i < _max_reconnects; i++) {
try {
_IO = new MysqlIO(_Host, _port);
_IO.init(_User, _Password);
_IO.sendCommand(MysqlDefs.INIT_DB, _Database, null);
_IO.sqlQuery(_PING_COMMAND, MysqlDefs.MAX_ROWS);
connection_good = true;
break;
}
catch (Exception EEE) {}
try {
Thread.currentThread().sleep((long)timeout * 1000);
timeout = timeout * timeout;
}
catch (InterruptedException IE) {}
}
if (!connection_good) { // We've really failed!
throw new SQLException("Server connection failure during transaction. \nAttemtped reconnect " + _max_reconnects + " times. Giving up.", "08001");
}
}
}
try {
int real_max_rows = ( max_rows == -1 ) ?
MysqlDefs.MAX_ROWS : max_rows;
if (Packet == null) {
String Encoding = null;
if (useUnicode()) {
Encoding = getEncoding();
}
return _IO.sqlQuery(Sql, real_max_rows, Encoding);
}
else {
return _IO.sqlQueryDirect(Packet, real_max_rows);
}
}
catch (java.io.EOFException EOFE) {
throw new java.sql.SQLException("Lost connection to server during query", "08007");
}
catch (Exception E) {
String ExceptionType = E.getClass().getName();
String ExceptionMessage = E.getMessage();
throw new java.sql.SQLException("Error during query: Unexpected Exception: " + ExceptionType + " message given: " + ExceptionMessage, "S1000");
}
}
}
String getURL()
{
return _MyURL;
}
String getUser()
{
return _User;
}
String getServerVersion()
{
return _IO.getServerVersion();
}
int getServerMajorVersion()
{
return _IO.getServerMajorVersion();
}
int getServerMinorVersion()
{
return _IO.getServerMinorVersion();
}
int getServerSubMinorVersion()
{
return _IO.getServerSubMinorVersion();
}
void maxRowsChanged()
{
_max_rows_changed = true;
}
boolean useMaxRows()
{
return _max_rows_changed;
}
boolean useUnicode()
{
return _do_unicode;
}
String getEncoding()
{
return _Encoding;
}
Object getMutex()
{
return _IO;
}
}
|
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.