Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

Connection.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet. 
00022  * Contributor(s): Julie Marguerite, Guillaume Bort, Duncan Smith, Vadim Kassin, Nicolas Modrzyk, Jaco Swart
00023  */
00024 
00025 package org.objectweb.cjdbc.driver;
00026 
00027 import java.io.IOException;
00028 import java.net.Socket;
00029 import java.sql.ResultSet;
00030 import java.sql.SQLException;
00031 import java.sql.SQLWarning;
00032 import java.sql.Savepoint;
00033 import java.util.ArrayList;
00034 import java.util.Hashtable;
00035 import java.util.Properties;
00036 
00037 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException;
00038 import org.objectweb.cjdbc.common.sql.AbstractRequest;
00039 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00040 import org.objectweb.cjdbc.common.sql.NotImplementedException;
00041 import org.objectweb.cjdbc.common.sql.SelectRequest;
00042 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00043 import org.objectweb.cjdbc.common.sql.filters.AbstractBlobFilter;
00044 import org.objectweb.cjdbc.common.sql.filters.HexaBlobFilter;
00045 import org.objectweb.cjdbc.common.stream.CJDBCInputStream;
00046 import org.objectweb.cjdbc.common.stream.CJDBCOutputStream;
00047 import org.objectweb.cjdbc.common.util.Constants;
00048 import org.objectweb.cjdbc.driver.protocol.CommandCompleted;
00049 import org.objectweb.cjdbc.driver.protocol.Commands;
00050 
00051 /**
00052  * This <code>Connection</code> class implements a virtual connection that is
00053  * just used to store the needed information when the real connection will have
00054  * to be established by the Controller to execute a query.
00055  * <p>
00056  * This code has been inspired from the PostgreSQL JDBC driver by Peter T.
00057  * Mount.
00058  * 
00059  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00060  * @author <a href="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
00061  * @author <a href="mailto:vadim@kase.kz">Vadim Kassin </a>
00062  * @author <a href="mailto:duncan@mightybot.com">Duncan Smith </a>
00063  * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
00064  * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
00065  * @version 1.0
00066  */
00067 public class Connection implements java.sql.Connection
00068 {
00069   // Member variables describing the state of the connection
00070 
00071   /** Commit mode of the connection (<code>true</code>= automatic). */
00072   protected boolean autoCommit = true;
00073 
00074   /** Status of the connection. */
00075   protected boolean isClosed = false;
00076 
00077   /** Is the connection in read-only mode ? */
00078   protected boolean readOnly = false;
00079 
00080   /** Has a write request been executed in the current transaction? */
00081   boolean writeExecutedInTransaction = false;
00082 
00083   /** Isolation level. */
00084   protected int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
00085 
00086   /** transaction identifier. */
00087   protected long transactionId = 0;
00088 
00089   /** Does the controller require the SQL skeleton? */
00090   protected boolean needSqlSkeleton = false;
00091 
00092   /** List of <code>Warnings</code> for this connection. */
00093   protected SQLWarning firstWarning = null;
00094 
00095   /** Meta-data of C-JDBC connections. */
00096   protected DatabaseMetaData metaData = null;
00097 
00098   /** Driver that created us. */
00099   protected Driver driver = null;
00100 
00101   /** C-JDBC URL of the database. */
00102   protected String url = null;
00103 
00104   /** Virtual database user used for this connection. */
00105   protected String vdbUser = null;
00106   protected String vdbPassword = null;
00107 
00108   /** Connection with the controller. */
00109   protected Socket socket;
00110 
00111   /** Socket input stream. */
00112   protected CJDBCInputStream socketInput;
00113 
00114   /** Socket output stream. */
00115   protected CJDBCOutputStream socketOutput;
00116 
00117   private int reconnectRetries = 0;
00118   // Maximum number of reconnect attempts when an IOException occurs
00119   // while communicating with the controller
00120   private static final int MAX_RECONNECT_ATTEMPTS = 2;
00121 
00122   private AbstractBlobFilter blobFilter;
00123 
00124   // Escape processing tuning
00125   protected boolean escapeBackslash = true;
00126   protected boolean escapeSingleQuote = true;
00127 
00128   //Parsing Query values
00129   protected boolean driverProcessed = true;
00130 
00131   /** Tag maker for PreparedStatement parameters */
00132   public static final String TAG_MARKER = "!%";
00133   /** Escape for tag maker */
00134   public static final String TAG_MARKER_ESCAPE = TAG_MARKER + ";";
00135   /** Tag for PreparedStatement parameters start delimiter */
00136   public static final String START_PARAM_TAG = "<" + TAG_MARKER;
00137   /** Tag for PreparedStatement parameters end delimiter */
00138   public static final String END_PARAM_TAG = "|" + TAG_MARKER + ">";
00139 
00140   // PreparedStatement.setBoolean values
00141   protected String preparedStatementBooleanTrue = "'1'";
00142   protected String preparedStatementBooleanFalse = "'0'";
00143 
00144   protected String escapeChar = "\'";
00145 
00146   protected static final String LINE_SEPARATOR = System
00147       .getProperty("line.separator");
00148 
00149   private boolean closeSocketOnGC = true;
00150 
00151   /*****************************************************************************
00152    * *************** * Constructor and get/set methods * ***********************
00153    * ****************************************************************************
00154    */
00155 
00156   /**
00157    * Creates a new <code>Connection</code> instance.
00158    */
00159   public Connection()
00160   {
00161   }
00162 
00163   /**
00164    * Creates a new <code>Connection</code> instance.
00165    * 
00166    * @param driver calling driver
00167    * @param socket connection with the controller
00168    * @param in socket input stream
00169    * @param out socket output stream
00170    * @param url C-JDBC URL of the database
00171    * @param userName user login
00172    * @param password user password
00173    * @param sqlSkeletonNeeded true if SQL skeletons must be sent to the
00174    *                 controller
00175    * @param filter to use to encode and decode blobs
00176    */
00177   public Connection(Driver driver, Socket socket, CJDBCInputStream in,
00178       CJDBCOutputStream out, String url, String userName, String password,
00179       boolean sqlSkeletonNeeded, AbstractBlobFilter filter)
00180   {
00181     this.driver = driver;
00182     this.socket = socket;
00183     this.socketInput = in;
00184     this.socketOutput = out;
00185     this.url = url;
00186     this.vdbUser = userName;
00187     this.vdbPassword = password;
00188     this.needSqlSkeleton = sqlSkeletonNeeded;
00189     this.blobFilter = filter;
00190   }
00191 
00192   /**
00193    * @see java.lang.Object#finalize()
00194    */
00195   protected void finalize() throws Throwable
00196   {
00197     if (this.closeSocketOnGC)
00198     {
00199       Throwable t = null;
00200       try
00201       {
00202         rollback();
00203       }
00204       catch (Exception e)
00205       {
00206         t = e;
00207       }
00208       try
00209       {
00210         close();
00211       }
00212       catch (Exception e)
00213       {
00214         t = e;
00215       }
00216 
00217       if (t != null)
00218       {
00219         throw t;
00220       }
00221 
00222     }
00223     super.finalize();
00224   }
00225 
00226   /**
00227    * Gets the C-JDBC URL of the database of the connection.
00228    * 
00229    * @return value of url.
00230    */
00231   public String getURL()
00232   {
00233     return url;
00234   }
00235 
00236   /**
00237    * Gets the user name used to login to the database.
00238    * 
00239    * @return login name
00240    */
00241   public String getUserName()
00242   {
00243     return vdbUser;
00244   }
00245 
00246   /**
00247    * Gets the password used to login to the database.
00248    * 
00249    * @return password
00250    */
00251   public String getPassword()
00252   {
00253     return vdbPassword;
00254   }
00255 
00256   /**
00257    * Get the controller description to which this connection is connected to
00258    * 
00259    * @return <code>String</code> like <code>localhost:25322</code> or null
00260    *               if not connected
00261    */
00262   public String getConnectedController()
00263   {
00264     if (socket == null)
00265       return null;
00266     else
00267       return socket.getInetAddress().getHostName() + ":" + socket.getPort();
00268   }
00269 
00270   /*****************************************************************************
00271    * *********************************** * Connection interface methods * *
00272    * ***********************************
00273    */
00274 
00275   /**
00276    * After this call, <code>getWarnings()</code> returns <code>null</code>
00277    * until a new warning is reported for this connection.
00278    * 
00279    * @exception SQLException if a database access error occurs
00280    */
00281   public void clearWarnings() throws SQLException
00282   {
00283     firstWarning = null;
00284   }
00285 
00286   /**
00287    * Releases the connection. In fact, the connection is marked to be released
00288    * but will be effectively closed by the <code>ConnectionClosingThread</code>
00289    * if the connection has not been reused before.
00290    * 
00291    * @exception SQLException if an error occurs
00292    */
00293   public void close() throws SQLException
00294   {
00295     // We synchronize here in the case 2 threads try to call close()
00296     // concurrently on this connection.
00297     synchronized (this)
00298     {
00299       if (isClosed)
00300         return;
00301       else
00302         isClosed = true;
00303     }
00304 
00305     try
00306     {
00307       autoCommit = true;
00308       readOnly = false;
00309       socketOutput.writeInt(Commands.Reset);
00310       socketOutput.flush();
00311     }
00312     catch (Exception e)
00313     {
00314       throw new SQLException("Error while closing the connection: " + e);
00315     }
00316 
00317     synchronized (driver.pendingConnectionClosing)
00318     {
00319       if (!driver.connectionClosingThreadisAlive)
00320       { // First connection to close, start a new closing thread
00321         ConnectionClosingThread t = new ConnectionClosingThread(driver);
00322         t.start();
00323       }
00324       // Add to the list
00325       driver.pendingConnectionClosing.add(this);
00326     }
00327   }
00328 
00329   /**
00330    * Makes all changes made since the previous commit/rollback permanent and
00331    * releases any database locks currently held by the <code>Connection</code>.
00332    * This method should only be used when auto-commit has been disabled. (If
00333    * <code>autoCommit</code>==<code>true</code>, then we throw an
00334    * SQLException).
00335    * 
00336    * @exception SQLException if a database access error occurs or the connection
00337    *                      is in autocommit mode
00338    * @see Connection#setAutoCommit
00339    */
00340   public void commit() throws SQLException
00341   {
00342     if (autoCommit)
00343       throw new SQLException("Trying to commit a connection in autocommit mode");
00344 
00345     if (driver == null)
00346       throw new SQLException("No driver to send the commit request");
00347     try
00348     {
00349       socketOutput.writeInt(Commands.Commit);
00350       socketOutput.flush();
00351       // Commit is followed by a BEGIN
00352       Object r = socketInput.readObject();
00353       writeExecutedInTransaction = false;
00354       if (r instanceof Long)
00355         transactionId = ((Long) r).longValue();
00356       else
00357         throw new SQLException(
00358             "Error occured while trying to start transaction after commit on C-JDBC Controller ("
00359                 + r + ")");
00360     }
00361     catch (Exception e)
00362     {
00363       throw new SQLException("Error occured while commit of transaction '"
00364           + transactionId + "' was processed by C-JDBC Controller (" + e + ")");
00365     }
00366   }
00367 
00368   /**
00369    * SQL statements without parameters are normally executed using
00370    * <code>Statement</code> objects. If the same SQL statement is executed
00371    * many times, it is more efficient to use a <code>PreparedStatement</code>.
00372    * The <code>ResultSet</code> will be
00373    * <code>TYPE_FORWARD_ONLY</cde>/<code>CONCUR_READ_ONLY</code>.
00374    *    *
00375    * @return a new <code>Statement</code> object
00376    * @exception SQLException passed through from the constructor
00377    */
00378   public java.sql.Statement createStatement() throws SQLException
00379   {
00380     return new Statement(this);
00381   }
00382 
00383   /**
00384    * SQL statements without parameters are normally executed using
00385    * <code>Statement</code> objects. If the same SQL statement is executed
00386    * many times, it is more efficient to use a <code>PreparedStatement</code>.
00387    * 
00388    * @param resultSetType resultSetType to use
00389    * @param resultSetConcurrency resultSetConcurrency to use
00390    * @return a new <code>Statement</code> object
00391    * @exception SQLException passed through from the constructor
00392    */
00393   public java.sql.Statement createStatement(int resultSetType,
00394       int resultSetConcurrency) throws SQLException
00395   {
00396     Statement s = new Statement(this);
00397     s.setResultSetType(resultSetType);
00398     s.setResultSetConcurrency(resultSetConcurrency);
00399     return s;
00400   }
00401 
00402   /**
00403    * Gets the current auto-commit state.
00404    * 
00405    * @return current state of the auto-commit mode
00406    * @exception SQLException (why?)
00407    * @see Connection#setAutoCommit
00408    */
00409   public boolean getAutoCommit() throws SQLException
00410   {
00411     return this.autoCommit;
00412   }
00413 
00414   /**
00415    * A connection's database is able to provide information describing its
00416    * tables, its supported SQL grammar, its stored procedures, the capabilities
00417    * of this connection, etc. This information is made available through a
00418    * DatabaseMetaData object.
00419    * 
00420    * @return a <code>DatabaseMetaData</code> object for this connection
00421    * @exception SQLException if a database access error occurs
00422    */
00423   public java.sql.DatabaseMetaData getMetaData() throws SQLException
00424   {
00425     if (metaData == null)
00426     {
00427       metaData = new DatabaseMetaData(this);
00428     }
00429     return metaData;
00430   }
00431 
00432   /**
00433    * Return current catalog name.
00434    * 
00435    * @return name of the current <code>VirtualDatabase</code>
00436    * @throws SQLException if any error occurs
00437    * @see java.sql.Connection#getCatalog()
00438    */
00439   public String getCatalog() throws SQLException
00440   {
00441     if (driver == null)
00442       throw new SQLException("No driver to get the catalog.");
00443     try
00444     {
00445       socketOutput.writeInt(Commands.ConnectionGetCatalog);
00446       socketOutput.flush();
00447 
00448       Object rs = socketInput.readObject();
00449       if (rs instanceof String)
00450       {
00451         return (String) rs;
00452       }
00453       else if (rs instanceof SQLException)
00454         throw (SQLException) rs;
00455       else
00456         throw new SQLException("Connection.getCatalog: Unexpected response ("
00457             + rs + ")");
00458     }
00459     catch (Exception e)
00460     {
00461       throw new SQLException(
00462           "Connection.getCatalog: Error occured while request was processed by C-JDBC Controller ("
00463               + e + ")");
00464     }
00465   }
00466 
00467   /**
00468    * getCatalogs definition.
00469    * 
00470    * @return instace of <code>ResultSet<code>
00471    * @throws SQLException if fails (include ANY exception that can be thrown in the code)
00472    */
00473   public ResultSet getCatalogs() throws SQLException
00474   {
00475 
00476     if (driver == null)
00477       throw new SQLException("No driver to get the catalogs.");
00478     try
00479     {
00480       socketOutput.writeInt(Commands.ConnectionGetCatalogs);
00481       socketOutput.flush();
00482 
00483       Object rs = socketInput.readObject();
00484       if (rs instanceof ResultSet)
00485         return (ResultSet) rs;
00486       else if (rs instanceof SQLException)
00487         throw (SQLException) rs;
00488       else
00489         throw new SQLException("Connection.getCatalogs: Unexpected response ("
00490             + rs + ")");
00491     }
00492     catch (Exception e)
00493     {
00494       throw new SQLException(
00495           "Connection.getCatalogs: Error occured while request was processed by C-JDBC Controller ("
00496               + e + ")");
00497     }
00498   }
00499 
00500   protected java.sql.ResultSet getProcedures(String catalog,
00501       String schemaPattern, String procedureNamePattern) throws SQLException
00502   {
00503     if (driver == null)
00504       throw new SQLException("No driver to get the tables.");
00505     try
00506     {
00507       socketOutput.writeInt(Commands.DatabaseMetaDataGetProcedures);
00508       socketOutput.writeUTF(catalog);
00509       socketOutput.writeUTF(schemaPattern);
00510       socketOutput.writeUTF(procedureNamePattern);
00511       socketOutput.flush();
00512 
00513       Object rs = socketInput.readObject();
00514       if (rs instanceof ResultSet)
00515         return (ResultSet) rs;
00516       else if (rs instanceof SQLException)
00517         throw (SQLException) rs;
00518       else
00519         throw new SQLException(
00520             "Connection.getProcedures: Unexpected response (" + rs + ")");
00521     }
00522     catch (Exception e)
00523     {
00524       throw new SQLException(
00525           "Connection.getProcedures: Error occured while request was processed by C-JDBC Controller ("
00526               + e + ")");
00527     }
00528   }
00529 
00530   protected java.sql.ResultSet getProcedureColumns(String catalog,
00531       String schemaPattern, String procedureNamePattern,
00532       String columnNamePattern) throws SQLException
00533   {
00534     if (driver == null)
00535       throw new SQLException("No driver to get the tables.");
00536     try
00537     {
00538       socketOutput.writeInt(Commands.DatabaseMetaDataGetProcedureColumns);
00539       socketOutput.writeUTF(catalog);
00540       socketOutput.writeUTF(schemaPattern);
00541       socketOutput.writeUTF(procedureNamePattern);
00542       socketOutput.writeUTF(columnNamePattern);
00543       socketOutput.flush();
00544 
00545       Object rs = socketInput.readObject();
00546       if (rs instanceof ResultSet)
00547         return (ResultSet) rs;
00548       else if (rs instanceof SQLException)
00549         throw (SQLException) rs;
00550       else
00551         throw new SQLException(
00552             "Connection.getProcedureColumns: Unexpected response (" + rs + ")");
00553     }
00554     catch (Exception e)
00555     {
00556       throw new SQLException(
00557           "Connection.getProcedureColumns: Error occured while request was processed by C-JDBC Controller ("
00558               + e + ")");
00559     }
00560   }
00561 
00562   /**
00563    * Gets this Connection's current transaction isolation mode.
00564    * 
00565    * @return the current <code>TRANSACTION_*</code> mode value
00566    * @exception SQLException if a database access error occurs
00567    */
00568   public int getTransactionIsolation() throws SQLException
00569   {
00570     return isolationLevel;
00571   }
00572 
00573   /**
00574    * C-JDBC does NOT support type map.
00575    * 
00576    * @return an exception
00577    * @exception SQLException not supported
00578    */
00579   public java.util.Map getTypeMap() throws SQLException
00580   {
00581     throw new NotImplementedException("getTypeMap()");
00582   }
00583 
00584   /**
00585    * The first warning reported by calls on this connection is returned. <B>
00586    * Note: </B> Sebsequent warnings will be changed to this SQLWarning
00587    * 
00588    * @return the first SQLWarning or null
00589    * @exception SQLException if a database access error occurs
00590    */
00591   public SQLWarning getWarnings() throws SQLException
00592   {
00593     return firstWarning;
00594   }
00595 
00596   /**
00597    * Returns <code>true</code> if the connection is closed (no real meaning
00598    * from C-JDBC point of view)
00599    * 
00600    * @return <code>true</code> if connection has never been opened or
00601    *               <code>close()</code> has been called
00602    * @exception SQLException if an error occurs
00603    */
00604   public boolean isClosed() throws SQLException
00605   {
00606     return isClosed;
00607   }
00608 
00609   /**
00610    * Tests to see if the connection is in read only Mode. Note that we cannot
00611    * really put the database in read only mode, but we pretend we can by
00612    * returning the value of the <code>readOnly</code> flag.
00613    * 
00614    * @return <code>true</code> if the connection is read only
00615    * @exception SQLException if a database access error occurs
00616    */
00617   public boolean isReadOnly() throws SQLException
00618   {
00619     return readOnly;
00620   }
00621 
00622   /**
00623    * As we can't know for sure which database will execute this request (now or
00624    * later), we can't translate it in the native query language of the
00625    * underlying DBMS. Therefore the query is returned unchanged.
00626    * 
00627    * @param query the query to change
00628    * @return the original query
00629    * @exception SQLException never
00630    */
00631   public String nativeSQL(String query) throws SQLException
00632   {
00633     return query;
00634   }
00635 
00636   /**
00637    * Creates a CallableStatement that contains sql and produces a ResultSet that
00638    * is TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY.
00639    * 
00640    * @param sql SQL request
00641    * @return nothing
00642    * @exception SQLException not supported
00643    */
00644   public java.sql.CallableStatement prepareCall(String sql) throws SQLException
00645   {
00646     return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,
00647         java.sql.ResultSet.CONCUR_READ_ONLY);
00648   }
00649 
00650   /**
00651    * Stored procedure call are not yet supported by C-JDBC.
00652    * 
00653    * @param sql a <code>String</code> value
00654    * @param resultSetType an <code>int</code> value
00655    * @param resultSetConcurrency an <code>int</code> value
00656    * @return nothing
00657    * @exception SQLException not supported
00658    */
00659   public java.sql.CallableStatement prepareCall(String sql, int resultSetType,
00660       int resultSetConcurrency) throws SQLException
00661   {
00662     CallableStatement c = new CallableStatement(this, sql);
00663     c.setResultSetType(resultSetType);
00664     c.setResultSetConcurrency(resultSetConcurrency);
00665     return c;
00666   }
00667 
00668   /**
00669    * A SQL statement with or without <code>IN</code> parameters can be
00670    * pre-compiled and stored in a PreparedStatement object. This object can then
00671    * be used to efficiently execute this statement multiple times.
00672    * 
00673    * @param sql a SQL statement that may contain one or more '?' IN * parameter
00674    *                 placeholders
00675    * @return a new <code>PreparedStatement</code> object containing the
00676    *               pre-compiled statement.
00677    * @exception SQLException if a database access error occurs.
00678    */
00679   public java.sql.PreparedStatement prepareStatement(String sql)
00680       throws SQLException
00681   {
00682     return new PreparedStatement(this, sql);
00683   }
00684 
00685   /**
00686    * A SQL statement with or without IN parameters can be pre-compiled and
00687    * stored in a <code>PreparedStatement</code> object. This object can then
00688    * be used to efficiently execute this statement multiple times.
00689    * 
00690    * @param sql a SQL statement that may contain one or more '?' IN
00691    * @param resultSetType <code>ResultSetType</code> to use
00692    * @param resultSetConcurrency <code>ResultSetConcurrency</code> to use
00693    * @return a new <code>PreparedStatement</code> object
00694    * @exception SQLException passed through from the constructor
00695    */
00696   public java.sql.PreparedStatement prepareStatement(String sql,
00697       int resultSetType, int resultSetConcurrency) throws SQLException
00698   {
00699     PreparedStatement s = new PreparedStatement(this, sql);
00700     s.setResultSetType(resultSetType);
00701     s.setResultSetConcurrency(resultSetConcurrency);
00702     return s;
00703   }
00704 
00705   /**
00706    * Drops all changes made since the previous commit/rollback and releases any
00707    * database locks currently held by this connection. If the connection was in
00708    * autocommit mode, we throw a SQLException.
00709    * 
00710    * @exception SQLException if a database access error occurs or the connection
00711    *                      is in autocommit mode
00712    * @see Connection#commit
00713    */
00714   public void rollback() throws SQLException
00715   {
00716     if (autoCommit)
00717       throw new SQLException(
00718           "Trying to rollback a connection in autocommit mode");
00719 
00720     if (driver == null)
00721       throw new SQLException("No driver to send the rollback request");
00722 
00723     try
00724     {
00725       socketOutput.writeInt(Commands.Rollback);
00726       socketOutput.flush();
00727       // Rollback is followed by a BEGIN
00728       writeExecutedInTransaction = false;
00729       Object r = socketInput.readObject();
00730       if (r instanceof Long)
00731         transactionId = ((Long) r).longValue();
00732       else
00733         throw new SQLException(
00734             "Error occured while trying to start transaction after rollback on C-JDBC Controller ("
00735                 + r + ")");
00736     }
00737     catch (Exception e)
00738     {
00739       throw new SQLException("Error occured while rollback of transaction '"
00740           + transactionId + "' was processed by C-JDBC Controller (" + e + ")");
00741     }
00742   }
00743 
00744   /**
00745    * If a connection is in auto-commit mode, then all its SQL statements will be
00746    * executed and committed as individual transactions. Otherwise, its SQL
00747    * statements are grouped into transactions that are terminated by either
00748    * {@link #commit()}or {@link #rollback()}. By default, new connections are
00749    * in auto-commit mode. The commit occurs when the statement completes or the
00750    * next execute occurs, whichever comes first. In the case of statements
00751    * returning a <code>ResultSet</code>, the statement completes when the
00752    * last row of the <code>ResultSet</code> has been retrieved or the
00753    * <code>ResultSet</code> has been closed. In advanced cases, a single
00754    * statement may return multiple results as well as output parameter values.
00755    * Here the commit occurs when all results and output param values have been
00756    * retrieved.
00757    * 
00758    * @param autoCommit <code>true</code> enables auto-commit;
00759    *                 <code>false</code> disables it
00760    * @exception SQLException if a database access error occurs
00761    */
00762   public void setAutoCommit(boolean autoCommit) throws SQLException
00763   {
00764     if (this.autoCommit == autoCommit)
00765       return;
00766 
00767     this.autoCommit = autoCommit;
00768     if (driver == null)
00769       throw new SQLException("No driver to get a transaction id");
00770 
00771     if (autoCommit)
00772     {
00773       transactionId = 0;
00774       try
00775       {
00776         socketOutput.writeInt(Commands.SetAutoCommit);
00777         socketOutput.flush();
00778         Object r = socketInput.readObject();
00779         writeExecutedInTransaction = false;
00780         if (r instanceof Boolean || ((Boolean) r).booleanValue())
00781           return;
00782         else
00783           throw new SQLException(
00784               "Error occured while trying to change autocommit value on C-JDBC Controller ("
00785                   + r + ")");
00786       }
00787       catch (Exception e)
00788       {
00789         throw new SQLException(
00790             "Error occured while trying to change autocommit value on C-JDBC Controller ("
00791                 + e + ")");
00792       }
00793     }
00794     else
00795     {
00796 
00797       try
00798       {
00799         socketOutput.writeInt(Commands.Begin);
00800         socketOutput.flush();
00801         Object r = socketInput.readObject();
00802         if (r instanceof Long)
00803           transactionId = ((Long) r).longValue();
00804         else
00805           throw new SQLException(
00806               "Error occured while trying to start transaction on C-JDBC Controller ("
00807                   + r + ")");
00808         this.autoCommit = false;
00809       }
00810       catch (Exception e)
00811       {
00812         throw new SQLException(
00813             "Error occured while trying to start transaction on C-JDBC Controller ("
00814                 + e + ")");
00815       }
00816     }
00817   }
00818 
00819   /**
00820    * Change the current catalog
00821    * 
00822    * @param catalog a <code>String</code> value
00823    * @exception SQLException if fails or if catalog name is invalid
00824    */
00825   public void setCatalog(String catalog) throws SQLException
00826   {
00827     if (catalog == null)
00828       throw new SQLException("Invalid Catalog");
00829     Hashtable properties = driver.parseURL(url);
00830     properties.put(Driver.DATABASE_PROPERTY, catalog);
00831     url = driver.getUrlFromProperties(properties);
00832 
00833     if (driver == null)
00834       throw new SQLException("No driver to set the catalog.");
00835     try
00836     {
00837       socketOutput.writeInt(Commands.ConnectionSetCatalog);
00838       socketOutput.writeUTF(catalog);
00839       socketOutput.flush();
00840 
00841       Object rs = socketInput.readObject();
00842       if (rs instanceof Boolean)
00843       {
00844         if (((Boolean) rs).booleanValue() == false)
00845           throw new SQLException("Invalid Catalog");
00846       }
00847       else
00848         throw new SQLException("Connection.setCatalog: Unexpected response ("
00849             + rs + ")");
00850     }
00851     catch (Exception e)
00852     {
00853       throw new SQLException(
00854           "Connection.setCatalog: Error occured while request was processed by C-JDBC Controller ("
00855               + e + ")");
00856     }
00857   }
00858 
00859   /**
00860    * You can put a connection in read-only mode as a hint to enable database
00861    * optimizations
00862    * <p>
00863    * <B>Note: </B> setReadOnly cannot be called while in the middle of a
00864    * transaction with write requests.
00865    * 
00866    * @param readOnly <code>true</code> enables read-only mode;
00867    *                 <code>false</code> disables it
00868    * @exception SQLException if a database access error occurs
00869    */
00870   public void setReadOnly(boolean readOnly) throws SQLException
00871   {
00872     if ((autoCommit == false) && writeExecutedInTransaction)
00873       throw new SQLException(
00874           "setReadOnly cannot be called in a transaction that has executed write requests.");
00875 
00876     this.readOnly = readOnly;
00877   }
00878 
00879   /**
00880    * You can call this method to try to change the transaction isolation level
00881    * using one of the TRANSACTION_* values.
00882    * <p>
00883    * <B>Note: </B> this method cannot be called while in the middle of a
00884    * transaction.
00885    * 
00886    * @param level one of the TRANSACTION_* isolation values with * the exception
00887    *                 of TRANSACTION_NONE; some databases may * not support other values
00888    * @exception SQLException if a database access error occurs
00889    * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
00890    */
00891   public void setTransactionIsolation(int level) throws SQLException
00892   {
00893     isolationLevel = level;
00894   }
00895 
00896   /**
00897    * C-JDBC does NOT support type map.
00898    * 
00899    * @param map ignored
00900    * @exception SQLException not supported
00901    */
00902   public void setTypeMap(java.util.Map map) throws SQLException
00903   {
00904     throw new NotImplementedException("setTypeMap()");
00905   }
00906 
00907   /*
00908    * Connection C-JDBC internals
00909    */
00910 
00911   /**
00912    * Set the autocommit mode and read-only status on this request.
00913    * 
00914    * @param request The request to set
00915    */
00916   protected void setConnectionParametersOnRequest(AbstractRequest request)
00917   {
00918     request.setIsAutoCommit(autoCommit);
00919     request.setIsReadOnly(readOnly);
00920     request.setDriverProcessed(driverProcessed);
00921   }
00922 
00923   /**
00924    * Performs a read request and return the reply.
00925    * 
00926    * @param request the read request to execute
00927    * @return a <code>java.sql.ResultSet</code> value
00928    * @exception SQLException if an error occurs
00929    */
00930   protected java.sql.ResultSet execReadRequest(SelectRequest request)
00931       throws SQLException
00932   {
00933     if (driver == null)
00934       throw new SQLException("No driver to send the request '"
00935           + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH) + "'");
00936     try
00937     {
00938       setConnectionParametersOnRequest(request);
00939       socketOutput.writeInt(Commands.ExecReadRequest);
00940       readRequestOnStream(request);
00941       socketOutput.flush();
00942 
00943       Object in = socketInput.readObject();
00944       if (in instanceof NoMoreBackendException)
00945       {
00946         try
00947         {
00948           // If there is only one controller available rethrow the exception
00949           if (driver.getControllerConfig().size() == 1)
00950             throw (SQLException) in;
00951           else
00952           {
00953             // otherwise try to connect to an other controller and re-execute
00954             // the query
00955             reconnect();
00956             return execReadRequest(request);
00957           }
00958         }
00959         catch (SQLException e1)
00960         {
00961           // We deal with this exception in the follwoing if block
00962           in = e1;
00963         }
00964       }
00965       if (in instanceof IOException)
00966       {
00967         reconnect();
00968         return execReadRequest(request);
00969       }
00970       else if (in instanceof SQLException)
00971       {
00972         throw (SQLException) in;
00973       }
00974       else if (in instanceof Field[])
00975       { // Get the ResultSet metadata the row data
00976         Field[] fields = (Field[]) in;
00977         ArrayList data = null;
00978         boolean hasMoreData;
00979         String cursorName = null;
00980         try
00981         {
00982           data = (ArrayList) socketInput.readObject();
00983           hasMoreData = socketInput.readBoolean();
00984           if (hasMoreData)
00985             cursorName = socketInput.readUTF();
00986         }
00987         catch (IOException e)
00988         {
00989           reconnect();
00990           return execReadRequest(request);
00991         }
00992         catch (Exception e1)
00993         {
00994           throw new SQLException(
00995               "Connection.execReadRequest: Unexpected response (" + e1
00996                   + ") for request "
00997                   + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
00998         }
00999         return new org.objectweb.cjdbc.driver.DriverResultSet(fields, data,
01000             hasMoreData, cursorName);
01001       }
01002       else
01003       {
01004         throw new SQLException(
01005             "Connection.execReadRequest: Unexpected response (" + in
01006                 + ") for request "
01007                 + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01008       }
01009 
01010     }
01011     catch (RuntimeException e)
01012     {
01013       e.printStackTrace();
01014       throw new SQLException(
01015           "Connection.execReadRequest: Error occured while request '"
01016               + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01017               + "' was processed by C-JDBC Controller (" + e + ")");
01018     }
01019     catch (IOException e)
01020     { // Connection failed, try to reconnect and re-exec the query
01021       try
01022       {
01023         reconnect();
01024         return execReadRequest(request);
01025       }
01026       catch (SQLException e1)
01027       {
01028         throw new SQLException("Connection lost while executing request '"
01029             + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01030             + "' and automatic reconnect failed (" + e1 + ")");
01031       }
01032     }
01033     catch (ClassNotFoundException e)
01034     {
01035       e.printStackTrace();
01036       throw new SQLException(
01037           "Connection.execReadRequest: Unexpected response (" + e
01038               + ") for request "
01039               + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01040     }
01041   }
01042 
01043   private void reconnect() throws SQLException
01044   {
01045     // Get rid of current connection
01046     try
01047     {
01048       this.socket.close();
01049     }
01050     catch (IOException ignore)
01051     {
01052     }
01053     try
01054     {
01055       this.socketInput.close();
01056     }
01057     catch (IOException ignore)
01058     {
01059     }
01060     try
01061     {
01062       this.socketOutput.close();
01063     }
01064     catch (IOException ignore)
01065     {
01066     }
01067     synchronized (driver.pendingConnectionClosing)
01068     {
01069       if (driver.pendingConnectionClosing.remove(this))
01070         System.out.println("Warning! Closed call before reconnect");
01071     }
01072 
01073     // Get a new connection
01074     reconnectRetries++;
01075     if (reconnectRetries > MAX_RECONNECT_ATTEMPTS)
01076     {
01077       reconnectRetries = 0;
01078       throw new SQLException("Aborting after " + MAX_RECONNECT_ATTEMPTS
01079           + " attemps.");
01080     }
01081     Properties prop = new Properties();
01082     prop.setProperty(Driver.USER_PROPERTY, vdbUser);
01083     prop.setProperty(Driver.PASSWORD_PROPERTY, vdbPassword);
01084     Connection c = (Connection) driver.connect(url, prop);
01085     c.setCloseSocketOnGC(false);
01086     this.socket = c.socket;
01087     this.socketInput = c.socketInput;
01088     this.socketOutput = c.socketOutput;
01089     this.isClosed = false;
01090     try
01091     {
01092       socketOutput.writeInt(Commands.RestoreConnectionState);
01093       socketOutput.writeBoolean(autoCommit);
01094       if (!autoCommit)
01095         socketOutput.writeLong(transactionId);
01096     }
01097     catch (IOException e)
01098     {
01099       throw new SQLException("Failed to reconnect to controller (" + e + ")");
01100     }
01101     reconnectRetries = 0;
01102   }
01103 
01104   /**
01105    * Sets the closeSocketOnGC value.
01106    * 
01107    * @param closeSocketOnGC The closeSocketOnGC to set.
01108    */
01109   protected void setCloseSocketOnGC(boolean closeSocketOnGC)
01110   {
01111     this.closeSocketOnGC = closeSocketOnGC;
01112   }
01113 
01114   /**
01115    * Performs a write request and return the number of rows affected.
01116    * 
01117    * @param request the write request to execute
01118    * @return number of rows affected
01119    * @exception SQLException if an error occurs
01120    */
01121   protected int execWriteRequest(AbstractWriteRequest request)
01122       throws SQLException
01123   {
01124     if (driver == null)
01125       throw new SQLException("No driver to send the request '"
01126           + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH) + "'");
01127     try
01128     {
01129       setConnectionParametersOnRequest(request);
01130       socketOutput.writeInt(Commands.ExecWriteRequest);
01131       writeRequestOnStream(request, false);
01132       socketOutput.flush();
01133 
01134       Object r = socketInput.readObject();
01135       if (r instanceof Integer)
01136         return ((Integer) r).intValue();
01137       else if (r instanceof SQLException)
01138         throw (SQLException) r;
01139       else
01140         throw new SQLException(
01141             "Connection.execWriteRequest: Unexpected response (" + r
01142                 + ") for request "
01143                 + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01144     }
01145     catch (SQLException e)
01146     {
01147       throw e;
01148     }
01149     catch (IOException e)
01150     { // Connection failed, try to reconnect and re-exec the query
01151       try
01152       {
01153         reconnect();
01154         return execWriteRequest(request);
01155       }
01156       catch (SQLException e1)
01157       {
01158         throw new SQLException("Connection lost while executing request'"
01159             + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01160             + "' and automatic reconnect failed (" + e1 + ")");
01161       }
01162     }
01163     catch (Exception e)
01164     {
01165       throw new SQLException("execWriteRequest: Error occured while request '"
01166           + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01167           + "' was processed by C-JDBC Controller (" + e + ")");
01168     }
01169   }
01170 
01171   /**
01172    * Serialize a read request on the output stream by sending only the needed
01173    * parameters to reconstruct it on the controller
01174    * 
01175    * @param request the read request to send
01176    * @throws IOException if fails
01177    */
01178   private void readRequestOnStream(SelectRequest request) throws IOException
01179   {
01180     /* WRITE SELECT REQUEST BEGIN */
01181     socketOutput.writeUTF(request.getSQL());
01182     socketOutput.writeBoolean(request.getEscapeProcessing());
01183     socketOutput.writeUTF(LINE_SEPARATOR);
01184     socketOutput.writeInt(request.getTimeout());
01185     socketOutput.writeBoolean(request.isAutoCommit());
01186     socketOutput.writeBoolean(request.isDriverProcessed());
01187     socketOutput.writeInt(request.getMaxRows());
01188     socketOutput.writeInt(request.getFetchSize());
01189     String cursor = request.getCursorName();
01190     if (cursor != null)
01191     {
01192       socketOutput.writeBoolean(true);
01193       socketOutput.writeUTF(cursor);
01194     }
01195     else
01196       socketOutput.writeBoolean(false);
01197     // If PreparedStatements are not processed by the driver, the controller
01198     // will need the skeleton.
01199     if (needSqlSkeleton || !request.isDriverProcessed())
01200     {
01201       String skeleton = request.getSqlSkeleton();
01202       if (skeleton != null)
01203       {
01204         socketOutput.writeBoolean(true);
01205         socketOutput.writeUTF(skeleton);
01206       }
01207       else
01208         socketOutput.writeBoolean(false);
01209     }
01210     /* WRITE SELECT REQUEST END */
01211   }
01212 
01213   /**
01214    * Serialize a procedure on the output stream by sending only the needed
01215    * parameters to reconstruct it on the controller
01216    * 
01217    * @param proc the procedure to send
01218    * @param isRead true if this is a read stored procedure
01219    * @throws IOException if fails
01220    */
01221   private void procedureOnStream(StoredProcedure proc, boolean isRead)
01222       throws IOException
01223   {
01224     if (!isRead)
01225       writeExecutedInTransaction = true;
01226 
01227     /* WRITE PROCEDURE REQUEST BEGIN */
01228     socketOutput.writeUTF(proc.getSQL());
01229     socketOutput.writeBoolean(proc.getEscapeProcessing());
01230     socketOutput.writeUTF(LINE_SEPARATOR);
01231     socketOutput.writeInt(proc.getTimeout());
01232     socketOutput.writeBoolean(proc.isAutoCommit());
01233     socketOutput.writeBoolean(proc.isDriverProcessed());
01234     if (isRead)
01235     {
01236       socketOutput.writeInt(proc.getMaxRows());
01237       socketOutput.writeInt(proc.getFetchSize());
01238     }
01239     // If PreparedStatements are not processed by the driver, the controller
01240     // will need the skeleton.
01241     if (needSqlSkeleton || !proc.isDriverProcessed())
01242     {
01243       String skeleton = proc.getSqlSkeleton();
01244       if (skeleton != null)
01245       {
01246         socketOutput.writeBoolean(true);
01247         socketOutput.writeUTF(skeleton);
01248       }
01249       else
01250         socketOutput.writeBoolean(false);
01251     }
01252     /* WRITE PROCEDURE REQUEST END */
01253   }
01254 
01255   /**
01256    * Serialize a write request on the output stream by sending only the needed
01257    * parameters to reconstruct it on the controller
01258    * 
01259    * @param request the write request to send
01260    * @param withKeys true if this request expect keys to be returned (as a
01261    *                 ResultSet)
01262    * @throws IOException if fails
01263    */
01264   private void writeRequestOnStream(AbstractWriteRequest request,
01265       boolean withKeys) throws IOException
01266   {
01267     if (!autoCommit)
01268       writeExecutedInTransaction = true;
01269 
01270     /* WRITE ABSTRACT WRITE REQUEST BEGIN */
01271     boolean isCreate = request.isCreate();
01272     boolean isDelete = request.isDelete();
01273     boolean isDrop = request.isDrop();
01274     boolean isInsert = request.isInsert();
01275     boolean isUpdate = request.isUpdate();
01276     boolean isAlter = request.isAlter();
01277     int requestType = -1;
01278     if (isCreate)
01279       requestType = Commands.CreateRequest;
01280     else if (isDelete)
01281       requestType = Commands.DeleteRequest;
01282     else if (isDrop)
01283       requestType = Commands.DropRequest;
01284     else if (isInsert)
01285       requestType = Commands.InsertRequest;
01286     else if (isUpdate)
01287       requestType = Commands.UpdateRequest;
01288     else if (isAlter)
01289       requestType = Commands.AlterRequest;
01290 
01291     socketOutput.writeInt(requestType);
01292     socketOutput.writeUTF(request.getSQL());
01293     socketOutput.writeBoolean(request.getEscapeProcessing());
01294     socketOutput.writeUTF(LINE_SEPARATOR);
01295     socketOutput.writeInt(request.getTimeout());
01296     socketOutput.writeBoolean(request.isAutoCommit());
01297     socketOutput.writeBoolean(request.isDriverProcessed());
01298     if (withKeys)
01299     {
01300       socketOutput.writeInt(request.getMaxRows());
01301       socketOutput.writeInt(request.getFetchSize());
01302     }
01303 
01304     // If PreparedStatements are not processed by the driver, the controller
01305     // will need the skeleton.
01306     if (needSqlSkeleton || !request.isDriverProcessed())
01307     {
01308       String skeleton = request.getSqlSkeleton();
01309       if (skeleton != null)
01310       {
01311         socketOutput.writeBoolean(true);
01312         socketOutput.writeUTF(skeleton);
01313       }
01314       else
01315         socketOutput.writeBoolean(false);
01316     }
01317     /* WRITE ABSTRACT WRITE REQUEST END */
01318   }
01319 
01320   /**
01321    * Performs a write request and return the number of rows affected.
01322    * 
01323    * @param request the write request to execute
01324    * @return auto generated keys
01325    * @exception SQLException if an error occurs
01326    */
01327   protected ResultSet execWriteRequestWithKeys(AbstractWriteRequest request)
01328       throws SQLException
01329   {
01330     if (driver == null)
01331       throw new SQLException("No driver to send the request '"
01332           + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH) + "'");
01333     try
01334     {
01335       setConnectionParametersOnRequest(request);
01336       socketOutput.writeInt(Commands.ExecWriteRequestWithKeys);
01337       writeRequestOnStream(request, true);
01338       socketOutput.flush();
01339 
01340       Object in = socketInput.readObject();
01341       if (in instanceof SQLException)
01342         throw (SQLException) in;
01343       else if (in instanceof Field[])
01344       { // Get the ResultSet metadata the row data
01345         Field[] fields = (Field[]) in;
01346         ArrayList data = null;
01347         boolean hasMoreData;
01348         String cursorName = null;
01349         try
01350         {
01351           data = (ArrayList) socketInput.readObject();
01352           hasMoreData = socketInput.readBoolean();
01353           if (hasMoreData)
01354             cursorName = socketInput.readUTF();
01355         }
01356         catch (Exception e1)
01357         {
01358           throw new SQLException(
01359               "Connection.execWriteRequestWithKeys: Unexpected response (" + e1
01360                   + ") for request "
01361                   + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01362         }
01363         return new org.objectweb.cjdbc.driver.DriverResultSet(fields, data,
01364             hasMoreData, cursorName);
01365       }
01366       else
01367         throw new SQLException(
01368             "Connection.execWriteRequestWithKeys: Unexpected response (" + in
01369                 + ") for request "
01370                 + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01371     }
01372     catch (Exception e)
01373     {
01374       throw new SQLException(
01375           "execWriteRequestWithKeys: Error occured while request '"
01376               + request.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01377               + "' was processed by C-JDBC Controller (" + e + ")");
01378     }
01379   }
01380 
01381   /**
01382    * Call a stored procedure that returns a ResultSet.
01383    * 
01384    * @param proc the stored procedure call
01385    * @return a <code>java.sql.ResultSet</code> value
01386    * @exception SQLException if an error occurs
01387    */
01388   public ResultSet execReadStoredProcedure(StoredProcedure proc)
01389       throws SQLException
01390   {
01391     if (driver == null)
01392       throw new SQLException("No driver to send the request '"
01393           + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH) + "'");
01394     try
01395     {
01396       setConnectionParametersOnRequest(proc);
01397       socketOutput.writeInt(Commands.ExecReadStoredProcedure);
01398       procedureOnStream(proc, true);
01399       socketOutput.flush();
01400 
01401       Object in = socketInput.readObject();
01402       if (in instanceof SQLException)
01403         throw (SQLException) in;
01404       else if (in instanceof Field[])
01405       { // Get the ResultSet metadata the row data
01406         Field[] fields = (Field[]) in;
01407         ArrayList data = null;
01408         boolean hasMoreData;
01409         String cursorName = null;
01410         try
01411         {
01412           data = (ArrayList) socketInput.readObject();
01413           hasMoreData = socketInput.readBoolean();
01414           if (hasMoreData)
01415             cursorName = socketInput.readUTF();
01416         }
01417         catch (Exception e1)
01418         {
01419           throw new SQLException(
01420               "Connection.execReadStoredProcedure: Unexpected response (" + e1
01421                   + ") for request "
01422                   + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01423         }
01424         return new org.objectweb.cjdbc.driver.DriverResultSet(fields, data,
01425             hasMoreData, cursorName);
01426       }
01427       else
01428         throw new SQLException(
01429             "Connection.execReadStoredProcedure: Unexpected response (" + in
01430                 + ") for request "
01431                 + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01432     }
01433     catch (RuntimeException e)
01434     {
01435       throw new SQLException(
01436           "Connection.execReadStoredProcedure: Error occured while request '"
01437               + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01438               + "' was processed by C-JDBC Controller (" + e + ")");
01439     }
01440     catch (IOException e)
01441     { // Connection failed, try to reconnect and re-exec the query
01442       try
01443       {
01444         reconnect();
01445         return execReadStoredProcedure(proc);
01446       }
01447       catch (SQLException e1)
01448       {
01449         throw new SQLException("Connection lost while executing request'"
01450             + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01451             + "' and automatic reconnect failed (" + e1 + ")");
01452       }
01453     }
01454     catch (ClassNotFoundException e)
01455     {
01456       throw new SQLException(
01457           "Connection.execReadStoredProcedure: Unexpected response (" + e
01458               + ") for request "
01459               + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01460     }
01461   }
01462 
01463   /**
01464    * Call a stored procedure that performs an update.
01465    * 
01466    * @param proc the stored procedure call
01467    * @return number of rows affected
01468    * @exception SQLException if an error occurs
01469    */
01470   protected int execWriteStoredProcedure(StoredProcedure proc)
01471       throws SQLException
01472   {
01473     if (driver == null)
01474       throw new SQLException("No driver to send the request '"
01475           + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH) + "'");
01476     try
01477     {
01478       setConnectionParametersOnRequest(proc);
01479       socketOutput.writeInt(Commands.ExecWriteStoredProcedure);
01480       procedureOnStream(proc, false);
01481       socketOutput.flush();
01482 
01483       Object r = socketInput.readObject();
01484       if (r instanceof Integer)
01485         return ((Integer) r).intValue();
01486       else if (r instanceof SQLException)
01487         throw (SQLException) r;
01488       else
01489         throw new SQLException(
01490             "Connection.execWriteStoredProcedure: Unexpected response (" + r
01491                 + ") for request "
01492                 + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH));
01493     }
01494     catch (Exception e)
01495     {
01496       throw new SQLException(
01497           "execWriteStoredProcedure: Error occured while request '"
01498               + proc.getSQLShortForm(Constants.SQL_SHORT_FORM_LENGTH)
01499               + "' was processed by C-JDBC Controller (" + e + ")");
01500     }
01501   }
01502 
01503   protected ResultSet getColumns(String catalog, String schemaPattern,
01504       String tableNamePattern, String columnNamePattern) throws SQLException
01505   {
01506     if (driver == null)
01507       throw new SQLException("No driver to get the tables.");
01508     try
01509     {
01510       socketOutput.writeInt(Commands.DatabaseMetaDataGetColumns);
01511       socketOutput.writeUTF(catalog);
01512       socketOutput.writeUTF(schemaPattern);
01513       socketOutput.writeUTF(tableNamePattern);
01514       socketOutput.writeUTF(columnNamePattern);
01515       socketOutput.flush();
01516 
01517       Object rs = socketInput.readObject();
01518       if (rs == null)
01519         return null;
01520       if (rs instanceof ResultSet)
01521         return (ResultSet) rs;
01522       else if (rs instanceof SQLException)
01523         throw (SQLException) rs;
01524       else
01525         throw new SQLException("Connection.getColumns: Unexpected response ("
01526             + rs + ")");
01527     }
01528     catch (Exception e)
01529     {
01530       throw new SQLException(
01531           "Connection.getColumns: Error occured while request was processed by C-JDBC Controller ("
01532               + e + ")");
01533     }
01534   }
01535 
01536   /**
01537    * @see java.sql.DatabaseMetaData#getPrimaryKeys
01538    */
01539   protected ResultSet getPrimaryKeys(String catalog, String schemaPattern,
01540       String tableNamePattern) throws SQLException
01541   {
01542     if (driver == null)
01543       throw new SQLException("No driver to get the tables.");
01544     try
01545     {
01546       socketOutput.writeInt(Commands.DatabaseMetaDataGetPrimaryKeys);
01547       socketOutput.writeUTF(catalog);
01548       socketOutput.writeUTF(schemaPattern);
01549       socketOutput.writeUTF(tableNamePattern);
01550       socketOutput.flush();
01551 
01552       Object rs = socketInput.readObject();
01553       if (rs == null)
01554         return null;
01555       if (rs instanceof ResultSet)
01556         return (ResultSet) rs;
01557       else if (rs instanceof SQLException)
01558         throw (SQLException) rs;
01559       else
01560         throw new SQLException(
01561             "Connection.getPrimaryKeys: Unexpected response (" + rs + ")");
01562     }
01563     catch (Exception e)
01564     {
01565       throw new SQLException(
01566           "Connection.getPrimaryKeys: Error occured while request was processed by C-JDBC Controller ("
01567               + e + ")");
01568     }
01569   }
01570 
01571   /**
01572    * @see org.objectweb.cjdbc.driver.DatabaseMetaData#getTables(String, String,
01573    *           String, String[])
01574    */
01575   protected ResultSet getTables(String catalog, String schemaPattern,
01576       String tableNamePattern, String[] types) throws SQLException
01577   {
01578     if (driver == null)
01579       throw new SQLException("No driver to get the tables.");
01580     try
01581     {
01582       socketOutput.writeInt(Commands.DatabaseMetaDataGetTables);
01583       socketOutput.writeUTF(catalog);
01584       socketOutput.writeUTF(schemaPattern);
01585       socketOutput.writeUTF(tableNamePattern);
01586       socketOutput.writeObject(types);
01587       socketOutput.flush();
01588 
01589       Object rs = socketInput.readObject();
01590       if (rs == null)
01591         return null;
01592       if (rs instanceof ResultSet)
01593         return (ResultSet) rs;
01594       else if (rs instanceof SQLException)
01595         throw (SQLException) rs;
01596       else
01597         throw new SQLException("Connection.getTables: Unexpected response ("
01598             + rs + ")");
01599     }
01600     catch (Exception e)
01601     {
01602       throw new SQLException(
01603           "Connection.getTables: Error occured while request was processed by C-JDBC Controller ("
01604               + e + ")");
01605     }
01606   }
01607 
01608   /**
01609    * Retrieve a metadata from the controller
01610    * 
01611    * @param key the name of the metadata to retrieve
01612    * @return an Object that will be an <tt>Integer</tt> or <tt>Boolean</tt>
01613    *               or <tt>String</tt>
01614    * @throws SQLException if fails
01615    */
01616   public Object getStaticMetadata(String key) throws SQLException
01617   {
01618     try
01619     {
01620       socketOutput.writeInt(Commands.DatabaseStaticMetadata);
01621       socketOutput.writeUTF(key);
01622       socketOutput.flush();
01623 
01624       Object s = socketInput.readObject();
01625       if (s instanceof SQLException)
01626         throw (SQLException) s;
01627       else
01628         return s;
01629     }
01630     catch (Exception e)
01631     {
01632       throw new SQLException(
01633           "Connection.getStaticMetadata: Error occured while request was processed by C-JDBC Controller ("
01634               + e + ")");
01635     }
01636 
01637   }
01638 
01639   /**
01640    * Get the C-JDBC controller version number.
01641    * 
01642    * @return a String containing the controller version
01643    * @exception SQLException if an error occurs
01644    */
01645   public String getControllerVersionNumber() throws SQLException
01646   {
01647     try
01648     {
01649       socketOutput.writeInt(Commands.GetControllerVersionNumber);
01650       socketOutput.flush();
01651 
01652       Object s = socketInput.readObject();
01653       if (s instanceof String)
01654         return (String) s;
01655       else
01656         throw new SQLException(
01657             "Connection.getControllerVersionNumber: Unexpected response (" + s
01658                 + ")");
01659     }
01660     catch (Exception e)
01661     {
01662       throw new SQLException(
01663           "Connection.getControllerVersionNumber: Error occured while request was processed by C-JDBC Controller ("
01664               + e + ")");
01665     }
01666   }
01667 
01668   //--------------------------JDBC 3.0-----------------------------
01669 
01670   /**
01671    * Changes the holdability of <code>ResultSet</code> objects created using
01672    * this <code>Connection</code> object to the given holdability.
01673    * 
01674    * @param holdability a <code>ResultSet</code> holdability constant; one of
01675    *                 <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
01676    *                 <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
01677    * @throws SQLException if a database access occurs, the given parameter is
01678    *                  not a <code>ResultSet</code> constant indicating holdability,
01679    *                  or the given holdability is not supported
01680    * @see #getHoldability
01681    * @see ResultSet
01682    * @since JDK 1.4
01683    */
01684   public void setHoldability(int holdability) throws SQLException
01685   {
01686     throw new NotImplementedException("setHoldability");
01687   }
01688 
01689   /**
01690    * Retrieves the current holdability of <code>ResultSet</code> objects
01691    * created using this <code>Connection</code> object.
01692    * 
01693    * @return the holdability, one of
01694    *               <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
01695    *               <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
01696    * @throws SQLException if a database access occurs
01697    * @see #setHoldability
01698    * @see ResultSet
01699    * @since JDK 1.4
01700    */
01701   public int getHoldability() throws SQLException
01702   {
01703     throw new NotImplementedException("getHoldability");
01704   }
01705 
01706   /**
01707    * Creates an unnamed savepoint in the current transaction and returns the new
01708    * <code>Savepoint</code> object that represents it.
01709    * 
01710    * @return the new <code>Savepoint</code> object
01711    * @exception SQLException if a database access error occurs or this
01712    *                      <code>Connection</code> object is currently in auto-commit
01713    *                      mode
01714    * @see Savepoint
01715    * @since JDK 1.4
01716    */
01717   public Savepoint setSavepoint() throws SQLException
01718   {
01719     throw new NotImplementedException("setSavepoint");
01720   }
01721 
01722   /**
01723    * Creates a savepoint with the given name in the current transaction and
01724    * returns the new <code>Savepoint</code> object that represents it.
01725    * 
01726    * @param name a <code>String</code> containing the name of the savepoint
01727    * @return the new <code>Savepoint</code> object
01728    * @exception SQLException if a database access error occurs or this
01729    *                      <code>Connection</code> object is currently in auto-commit
01730    *                      mode
01731    * @see Savepoint
01732    * @since JDK 1.4
01733    */
01734   public Savepoint setSavepoint(String name) throws SQLException
01735   {
01736     throw new NotImplementedException("setSavepoint");
01737   }
01738 
01739   /**
01740    * Undoes all changes made after the given <code>Savepoint</code> object was
01741    * set.
01742    * <p>
01743    * This method should be used only when auto-commit has been disabled.
01744    * 
01745    * @param savepoint the <code>Savepoint</code> object to roll back to
01746    * @exception SQLException if a database access error occurs, the
01747    *                      <code>Savepoint</code> object is no longer valid, or this
01748    *                      <code>Connection</code> object is currently in auto-commit
01749    *                      mode
01750    * @see Savepoint
01751    * @see #rollback()
01752    * @since JDK 1.4
01753    */
01754   public void rollback(Savepoint savepoint) throws SQLException
01755   {
01756     throw new NotImplementedException("rollback");
01757   }
01758 
01759   /**
01760    * Removes the given <code>Savepoint</code> object from the current
01761    * transaction. Any reference to the savepoint after it have been removed will
01762    * cause an <code>SQLException</code> to be thrown.
01763    * 
01764    * @param savepoint the <code>Savepoint</code> object to be removed
01765    * @exception SQLException if a database access error occurs or the given
01766    *                      <code>Savepoint</code> object is not a valid savepoint in
01767    *                      the current transaction
01768    * @since JDK 1.4
01769    */
01770   public void releaseSavepoint(Savepoint savepoint) throws SQLException
01771   {
01772     throw new NotImplementedException("releaseSavepoint");
01773   }
01774 
01775   /**
01776    * Creates a <code>Statement</code> object that will generate
01777    * <code>ResultSet</code> objects with the given type, concurrency, and
01778    * holdability.
01779    * <p>
01780    * This method is the same as the <code>createStatement</code> method above,
01781    * but it allows the default result set type, concurrency, and holdability to
01782    * be overridden.
01783    * 
01784    * @param resultSetType one of the following <code>ResultSet</code>
01785    *                 constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
01786    *                 <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
01787    *                 <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
01788    * @param resultSetConcurrency one of the following <code>ResultSet</code>
01789    *                 constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
01790    *                 <code>ResultSet.CONCUR_UPDATABLE</code>
01791    * @param resultSetHoldability one of the following <code>ResultSet</code>
01792    *                 constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
01793    *                 <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
01794    * @return a new <code>Statement</code> object that will generate
01795    *               <code>ResultSet</code> objects with the given type, concurrency,
01796    *               and holdability
01797    * @exception SQLException if a database access error occurs or the given
01798    *                      parameters are not <code>ResultSet</code> constants
01799    *                      indicating type, concurrency, and holdability
01800    * @see ResultSet
01801    * @since JDK 1.4
01802    */
01803   public java.sql.Statement createStatement(int resultSetType,
01804       int resultSetConcurrency, int resultSetHoldability) throws SQLException
01805   {
01806     throw new NotImplementedException("createStatement");
01807   }
01808 
01809   /**
01810    * Creates a <code>PreparedStatement</code> object that will generate
01811    * <code>ResultSet</code> objects with the given type, concurrency, and
01812    * holdability.
01813    * <p>
01814    * This method is the same as the <code>prepareStatement</code> method
01815    * above, but it allows the default result set type, concurrency, and
01816    * holdability to be overridden.
01817    * 
01818    * @param sql a <code>String</code> object that is the SQL statement to be
01819    *                 sent to the database; may contain one or more ? IN parameters
01820    * @param resultSetType one of the following <code>ResultSet</code>
01821    *                 constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
01822    *                 <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
01823    *                 <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
01824    * @param resultSetConcurrency one of the following <code>ResultSet</code>
01825    *                 constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
01826    *                 <code>ResultSet.CONCUR_UPDATABLE</code>
01827    * @param resultSetHoldability one of the following <code>ResultSet</code>
01828    *                 constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
01829    *                 <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
01830    * @return a new <code>PreparedStatement</code> object, containing the
01831    *               pre-compiled SQL statement, that will generate
01832    *               <code>ResultSet</code> objects with the given type, concurrency,
01833    *               and holdability
01834    * @exception SQLException if a database access error occurs or the given
01835    *                      parameters are not <code>ResultSet</code> constants
01836    *                      indicating type, concurrency, and holdability
01837    * @see ResultSet
01838    * @since JDK 1.4
01839    */
01840   public java.sql.PreparedStatement prepareStatement(String sql,
01841       int resultSetType, int resultSetConcurrency, int resultSetHoldability)
01842       throws SQLException
01843   {
01844     throw new NotImplementedException("prepareStatement");
01845   }
01846 
01847   /**
01848    * Creates a <code>CallableStatement</code> object that will generate
01849    * <code>ResultSet</code> objects with the given type and concurrency. This
01850    * method is the same as the <code>prepareCall</code> method above, but it
01851    * allows the default result set type, result set concurrency type and
01852    * holdability to be overridden.
01853    * 
01854    * @param sql a <code>String</code> object that is the SQL statement to be
01855    *                 sent to the database; may contain on or more ? parameters
01856    * @param resultSetType one of the following <code>ResultSet</code>
01857    *                 constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
01858    *                 <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
01859    *                 <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
01860    * @param resultSetConcurrency one of the following <code>ResultSet</code>
01861    *                 constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
01862    *                 <code>ResultSet.CONCUR_UPDATABLE</code>
01863    * @param resultSetHoldability one of the following <code>ResultSet</code>
01864    *                 constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
01865    *                 <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
01866    * @return a new <code>CallableStatement</code> object, containing the
01867    *               pre-compiled SQL statement, that will generate
01868    *               <code>ResultSet</code> objects with the given type, concurrency,
01869    *               and holdability
01870    * @exception SQLException if a database access error occurs or the given
01871    *                      parameters are not <code>ResultSet</code> constants
01872    *                      indicating type, concurrency, and holdability
01873    * @see ResultSet
01874    * @since JDK 1.4
01875    */
01876   public java.sql.CallableStatement prepareCall(String sql, int resultSetType,
01877       int resultSetConcurrency, int resultSetHoldability) throws SQLException
01878   {
01879     throw new NotImplementedException("prepareCall");
01880   }
01881 
01882   /**
01883    * Creates a default <code>PreparedStatement</code> object that has the
01884    * capability to retrieve auto-generated keys. The given constant tells the
01885    * driver whether it should make auto-generated keys available for retrieval.
01886    * This parameter is ignored if the SQL statement is not an
01887    * <code>INSERT</code> statement.
01888    * <p>
01889    * <b>Note: </b> This method is optimized for handling parametric SQL
01890    * statements that benefit from precompilation. If the driver supports
01891    * precompilation, the method <code>prepareStatement</code> will send the
01892    * statement to the database for precompilation. Some drivers may not support
01893    * precompilation. In this case, the statement may not be sent to the database
01894    * until the <code>PreparedStatement</code> object is executed. This has no
01895    * direct effect on users; however, it does affect which methods throw certain
01896    * SQLExceptions.
01897    * <p>
01898    * Result sets created using the returned <code>PreparedStatement</code>
01899    * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
01900    * concurrency level of <code>CONCUR_READ_ONLY</code>.
01901    * 
01902    * @param sql an SQL statement that may contain one or more '?' IN parameter
01903    *                 placeholders
01904    * @param autoGeneratedKeys a flag indicating whether auto-generated keys
01905    *                 should be returned; one of
01906    *                 <code>Statement.RETURN_GENERATED_KEYS</code> or
01907    *                 <code>Statement.NO_GENERATED_KEYS</code>
01908    * @return a new <code>PreparedStatement</code> object, containing the
01909    *               pre-compiled SQL statement, that will have the capability of
01910    *               returning auto-generated keys
01911    * @exception SQLException if a database access error occurs or the given
01912    *                      parameter is not a <code>Statement</code> constant
01913    *                      indicating whether auto-generated keys should be returned
01914    * @since JDK 1.4
01915    */
01916   public java.sql.PreparedStatement prepareStatement(String sql,
01917       int autoGeneratedKeys) throws SQLException
01918   {
01919     PreparedStatement ps = new PreparedStatement(this, sql);
01920     ps.setGeneratedKeysFlag(autoGeneratedKeys);
01921     return ps;
01922   }
01923 
01924   /**
01925    * Creates a default <code>PreparedStatement</code> object capable of
01926    * returning the auto-generated keys designated by the given array. This array
01927    * contains the indexes of the columns in the target table that contain the
01928    * auto-generated keys that should be made available. This array is ignored if
01929    * the SQL statement is not an <code>INSERT</code> statement.
01930    * <p>
01931    * An SQL statement with or without IN parameters can be pre-compiled and
01932    * stored in a <code>PreparedStatement</code> object. This object can then
01933    * be used to efficiently execute this statement multiple times.
01934    * <p>
01935    * <b>Note: </b> This method is optimized for handling parametric SQL
01936    * statements that benefit from precompilation. If the driver supports
01937    * precompilation, the method <code>prepareStatement</code> will send the
01938    * statement to the database for precompilation. Some drivers may not support
01939    * precompilation. In this case, the statement may not be sent to the database
01940    * until the <code>PreparedStatement</code> object is executed. This has no
01941    * direct effect on users; however, it does affect which methods throw certain
01942    * SQLExceptions.
01943    * <p>
01944    * Result sets created using the returned <code>PreparedStatement</code>
01945    * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
01946    * concurrency level of <code>CONCUR_READ_ONLY</code>.
01947    * 
01948    * @param sql an SQL statement that may contain one or more '?' IN parameter
01949    *                 placeholders
01950    * @param columnIndexes an array of column indexes indicating the columns that
01951    *                 should be returned from the inserted row or rows
01952    * @return a new <code>PreparedStatement</code> object, containing the
01953    *               pre-compiled statement, that is capable of returning the
01954    *               auto-generated keys designated by the given array of column indexes
01955    * @exception SQLException if a database access error occurs
01956    * @since JDK 1.4
01957    */
01958   public java.sql.PreparedStatement prepareStatement(String sql,
01959       int columnIndexes[]) throws SQLException
01960   {
01961     throw new NotImplementedException("prepareStatement");
01962   }
01963 
01964   /**
01965    * Creates a default <code>PreparedStatement</code> object capable of
01966    * returning the auto-generated keys designated by the given array. This array
01967    * contains the names of the columns in the target table that contain the
01968    * auto-generated keys that should be returned. This array is ignored if the
01969    * SQL statement is not an <code>INSERT</code> statement.
01970    * <p>
01971    * An SQL statement with or without IN parameters can be pre-compiled and
01972    * stored in a <code>PreparedStatement</code> object. This object can then
01973    * be used to efficiently execute this statement multiple times.
01974    * <p>
01975    * <b>Note: </b> This method is optimized for handling parametric SQL
01976    * statements that benefit from precompilation. If the driver supports
01977    * precompilation, the method <code>prepareStatement</code> will send the
01978    * statement to the database for precompilation. Some drivers may not support
01979    * precompilation. In this case, the statement may not be sent to the database
01980    * until the <code>PreparedStatement</code> object is executed. This has no
01981    * direct effect on users; however, it does affect which methods throw certain
01982    * <code>SQLExceptions</code>.
01983    * <p>
01984    * Result sets created using the returned <code>PreparedStatement</code>
01985    * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
01986    * concurrency level of <code>CONCUR_READ_ONLY</code>.
01987    * 
01988    * @param sql an SQL statement that may contain one or more '?' IN parameter
01989    *                 placeholders
01990    * @param columnNames an array of column names indicating the columns that
01991    *                 should be returned from the inserted row or rows
01992    * @return a new <code>PreparedStatement</code> object, containing the
01993    *               pre-compiled statement, that is capable of returning the
01994    *               auto-generated keys designated by the given array of column names
01995    * @exception SQLException if a database access error occurs
01996    * @since JDK 1.4
01997    */
01998   public java.sql.PreparedStatement prepareStatement(String sql,
01999       String columnNames[]) throws SQLException
02000   {
02001     throw new NotImplementedException("prepareStatement");
02002   }
02003 
02004   /**
02005    * Returns the blobFilter value.
02006    * 
02007    * @return Returns the blobFilter.
02008    */
02009   public AbstractBlobFilter getBlobFilter()
02010   {
02011     if (blobFilter == null)
02012       blobFilter = new HexaBlobFilter();
02013     return blobFilter;
02014   }
02015 
02016   /**
02017    * Gets the table types available in this database. The results are ordered by
02018    * table type.
02019    * 
02020    * @return <code>ResultSet</code> each row has a single String column that
02021    *               is a catalog name
02022    * @throws SQLException if a database error occurs
02023    */
02024   public ResultSet getTableTypes() throws SQLException
02025   {
02026     if (driver == null)
02027       throw new SQLException("No driver to get the table types.");
02028     try
02029     {
02030       socketOutput.writeInt(Commands.DatabaseMetaDataGetTableTypes);
02031       socketOutput.flush();
02032 
02033       Object rs = socketInput.readObject();
02034       if (rs == null)
02035         return null;
02036       if (rs instanceof ResultSet)
02037         return (ResultSet) rs;
02038       else if (rs instanceof SQLException)
02039         throw (SQLException) rs;
02040       else
02041         throw new SQLException(
02042             "Connection.getTableTypes: Unexpected response (" + rs + ")");
02043     }
02044     catch (Exception e)
02045     {
02046       throw new SQLException(
02047           "Connection.getTableTypes: Error occured while request was processed by C-JDBC Controller ("
02048               + e + ")");
02049     }
02050   }
02051 
02052   /**
02053    * Gets a description of the access rights for each table available in a
02054    * catalog. Note that a table privilege applies to one or more columns in the
02055    * table. It would be wrong to assume that this priviledge applies to all
02056    * columns (this may be true for some systems but is not true for all.) Only
02057    * privileges matching the schema and table name criteria are returned. They
02058    * are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
02059    * 
02060    * @param catalog a catalog name; "" retrieves those without a catalog; null
02061    *                 means drop catalog name from the selection criteria
02062    * @param schemaPattern a schema name pattern; "" retrieves those without a
02063    *                 schema
02064    * @param tableNamePattern a table name pattern
02065    * @return <code>ResultSet</code> each row is a table privilege description
02066    * @throws SQLException if a database access error occurs
02067    */
02068   public ResultSet getTablePrivileges(String catalog, String schemaPattern,
02069       String tableNamePattern) throws SQLException
02070   {
02071     if (driver == null)
02072       throw new SQLException("No driver to get the table privileges.");
02073     try
02074     {
02075       socketOutput.writeInt(Commands.DatabaseMetaDataGetTablePrivileges);
02076       socketOutput.writeUTF(catalog);
02077       socketOutput.writeUTF(schemaPattern);
02078       socketOutput.writeUTF(tableNamePattern);
02079       socketOutput.flush();
02080 
02081       Object rs = socketInput.readObject();
02082       if (rs == null)
02083         return null;
02084       if (rs instanceof ResultSet)
02085         return (ResultSet) rs;
02086       else if (rs instanceof SQLException)
02087         throw (SQLException) rs;
02088       else
02089         throw new SQLException(
02090             "Connection.getTablePrivileges: Unexpected response (" + rs + ")");
02091     }
02092     catch (Exception e)
02093     {
02094       throw new SQLException(
02095           "Connection.getTablePrivileges: Error occured while request was processed by C-JDBC Controller ("
02096               + e + ")");
02097     }
02098   }
02099 
02100   /**
02101    * @see java.sql.DatabaseMetaData#getSchemas()
02102    */
02103   public ResultSet getSchemas() throws SQLException
02104   {
02105     if (driver == null)
02106       throw new SQLException("No driver to get the schemas.");
02107     try
02108     {
02109       socketOutput.writeInt(Commands.DatabaseMetaDataGetSchemas);
02110       socketOutput.flush();
02111 
02112       Object rs = socketInput.readObject();
02113       if (rs == null)
02114         return null;
02115       if (rs instanceof ResultSet)
02116         return (ResultSet) rs;
02117       else if (rs instanceof SQLException)
02118         throw (SQLException) rs;
02119       else
02120         throw new SQLException("Connection.getSchemas: Unexpected response ("
02121             + rs + ")");
02122     }
02123     catch (Exception e)
02124     {
02125       throw new SQLException(
02126           "Connection.getSchemas: Error occured while request was processed by C-JDBC Controller ("
02127               + e + ")");
02128     }
02129   }
02130 
02131   /**
02132    * @see DatabaseMetaData#getDatabaseProductName()
02133    */
02134   public String getDatabaseProductName() throws SQLException
02135   {
02136     try
02137     {
02138       socketOutput.writeInt(Commands.DatabaseMetaDataGetDatabaseProductName);
02139       socketOutput.flush();
02140 
02141       Object s = socketInput.readObject();
02142       if (s instanceof String)
02143         return (String) s;
02144       else
02145         throw new SQLException(
02146             "Connection.GetDatabaseProductName: Unexpected response (" + s
02147                 + ")");
02148     }
02149     catch (Exception e)
02150     {
02151       throw new SQLException(
02152           "Connection.getDatabaseProductName: Error occured while request was processed by C-JDBC Controller ("
02153               + e + ")");
02154     }
02155   }
02156 
02157   /**
02158    * Fetch next fetchSize rows of data and update the given ResultSet.
02159    * 
02160    * @param cursorName name of the ResultSet cursor
02161    * @param fetchSize number of rows to fetch
02162    * @param drsToUpdate DriverResultSet to update
02163    * @throws SQLException if an error occurs
02164    */
02165   public void fetchNextData(String cursorName, int fetchSize,
02166       DriverResultSet drsToUpdate) throws SQLException
02167   {
02168     try
02169     {
02170       socketOutput.writeInt(Commands.FetchNextResultSetRows);
02171       socketOutput.writeUTF(cursorName);
02172       socketOutput.writeInt(fetchSize);
02173       socketOutput.flush();
02174 
02175       Object data = socketInput.readObject();
02176       if (data instanceof ArrayList)
02177       {
02178         boolean hasMoreData = socketInput.readBoolean();
02179         drsToUpdate.setData((ArrayList) data);
02180         drsToUpdate.setHasMoreData(hasMoreData);
02181       }
02182       else if (data instanceof SQLException)
02183         throw (SQLException) data;
02184       else
02185         throw new SQLException(
02186             "Connection.fetchNextData: Unexpected response (" + data + ")");
02187     }
02188     catch (Exception e)
02189     {
02190       throw new SQLException(
02191           "Connection.fetchNextData: Error occured while request was processed by C-JDBC Controller ("
02192               + e + ")");
02193     }
02194   }
02195 
02196   /**
02197    * Closes the remote ResultSet given its cursor name.
02198    * 
02199    * @param cursorName cursor name of the ResultSet to close.
02200    * @throws SQLException if an error occurs
02201    */
02202   public void closeRemoteResultSet(String cursorName) throws SQLException
02203   {
02204     try
02205     {
02206       socketOutput.writeInt(Commands.CloseRemoteResultSet);
02207       socketOutput.writeUTF(cursorName);
02208       socketOutput.flush();
02209 
02210       Object data = socketInput.readObject();
02211       if (data instanceof CommandCompleted)
02212         return;
02213       else if (data instanceof SQLException)
02214         throw (SQLException) data;
02215       else
02216         throw new SQLException(
02217             "Connection.closeRemoteResultSet: Unexpected response (" + data
02218                 + ")");
02219     }
02220     catch (Exception e)
02221     {
02222       throw new SQLException(
02223           "Connection.closeRemoteResultSet: Error occured while request was processed by C-JDBC Controller ("
02224               + e + ")");
02225     }
02226   }
02227 
02228   /**
02229    * Returns the booleanFalse value.
02230    * 
02231    * @return Returns the booleanFalse.
02232    */
02233   public String getPreparedStatementBooleanFalse()
02234   {
02235     return preparedStatementBooleanFalse;
02236   }
02237 
02238   /**
02239    * Sets the booleanFalse value.
02240    * 
02241    * @param booleanFalse The booleanFalse to set.
02242    */
02243   public void setPreparedStatementBooleanFalse(String booleanFalse)
02244   {
02245     this.preparedStatementBooleanFalse = booleanFalse;
02246   }
02247 
02248   /**
02249    * Returns the booleanTrue value.
02250    * 
02251    * @return Returns the booleanTrue.
02252    */
02253   public String getPreparedStatementBooleanTrue()
02254   {
02255     return preparedStatementBooleanTrue;
02256   }
02257 
02258   /**
02259    * Sets the booleanTrue value.
02260    * 
02261    * @param booleanTrue The booleanTrue to set.
02262    */
02263   public void setPreparedStatementBooleanTrue(String booleanTrue)
02264   {
02265     this.preparedStatementBooleanTrue = booleanTrue;
02266   }
02267 
02268   /**
02269    * Returns the escapeBackslash value.
02270    * 
02271    * @return Returns the escapeBackslash.
02272    */
02273   public boolean isEscapeBackslash()
02274   {
02275     return escapeBackslash;
02276   }
02277 
02278   /**
02279    * Sets the escapeBackslash value.
02280    * 
02281    * @param escapeBackslash The escapeBackslash to set.
02282    */
02283   public void setEscapeBackslash(boolean escapeBackslash)
02284   {
02285     this.escapeBackslash = escapeBackslash;
02286   }
02287 
02288   /**
02289    * Returns the escapeSingleQuote value.
02290    * 
02291    * @return Returns the escapeSingleQuote.
02292    */
02293   public boolean isEscapeSingleQuote()
02294   {
02295     return escapeSingleQuote;
02296   }
02297 
02298   /**
02299    * Sets the escapeSingleQuote value.
02300    * 
02301    * @param escapeSingleQuote The escapeSingleQuote to set.
02302    */
02303   public void setEscapeSingleQuote(boolean escapeSingleQuote)
02304   {
02305     this.escapeSingleQuote = escapeSingleQuote;
02306   }
02307 
02308   /**
02309    * Sets the driverProcessed value
02310    * 
02311    * @param processedByDriver true if the PreparedStatement are processed by the
02312    *                 C-JDBC driver.
02313    */
02314   public void setDriverProcessed(boolean processedByDriver)
02315   {
02316     this.driverProcessed = processedByDriver;
02317   }
02318 
02319   /**
02320    * Returns the driverProcessed value.
02321    * 
02322    * @return Returns the driverProcessed.
02323    */
02324   public boolean isDriverProcessed()
02325   {
02326     return driverProcessed;
02327   }
02328 
02329   /**
02330    * Sets the escapeCharacter value
02331    * 
02332    * @param escapeChar the escapeChar value to set
02333    */
02334   public void setEscapeChar(String escapeChar)
02335   {
02336     this.escapeChar = escapeChar;
02337   }
02338 
02339   /**
02340    * @return Returns the escapeChar.
02341    */
02342   public String getEscapeChar()
02343   {
02344     return escapeChar;
02345   }
02346 }

Generated on Mon Apr 11 22:01:30 2005 for C-JDBC by  doxygen 1.3.9.1