KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > driver > Connection


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): Julie Marguerite, Guillaume Bort, Duncan Smith, Vadim Kassin,
23  * Nicolas Modrzyk, Jaco Swart, Jean-Bernard van Zuylen
24  * Completely refactored by Marc Herbert to remove the use of Java serialization.
25  */

26
27 package org.objectweb.cjdbc.driver;
28
29 import java.io.IOException JavaDoc;
30 import java.net.Socket JavaDoc;
31 import java.sql.ResultSet JavaDoc;
32 import java.sql.SQLException JavaDoc;
33 import java.sql.SQLWarning JavaDoc;
34 import java.sql.Savepoint JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.Properties JavaDoc;
39
40 import org.objectweb.cjdbc.common.exceptions.AuthenticationException;
41 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException;
42 import org.objectweb.cjdbc.common.exceptions.NoMoreControllerException;
43 import org.objectweb.cjdbc.common.exceptions.NotImplementedException;
44 import org.objectweb.cjdbc.common.exceptions.ProtocolException;
45 import org.objectweb.cjdbc.common.exceptions.driver.DriverSQLException;
46 import org.objectweb.cjdbc.common.exceptions.driver.protocol.BackendDriverException;
47 import org.objectweb.cjdbc.common.exceptions.driver.protocol.ControllerCoreException;
48 import org.objectweb.cjdbc.common.exceptions.driver.protocol.SerializableException;
49 import org.objectweb.cjdbc.common.sql.AbstractRequest;
50 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
51 import org.objectweb.cjdbc.common.sql.SelectRequest;
52 import org.objectweb.cjdbc.common.sql.StoredProcedure;
53 import org.objectweb.cjdbc.common.sql.filters.AbstractBlobFilter;
54 import org.objectweb.cjdbc.common.stream.CJDBCInputStream;
55 import org.objectweb.cjdbc.common.stream.CJDBCOutputStream;
56 import org.objectweb.cjdbc.common.util.Constants;
57 import org.objectweb.cjdbc.driver.connectpolicy.AbstractControllerConnectPolicy;
58 import org.objectweb.cjdbc.driver.protocol.Commands;
59 import org.objectweb.cjdbc.driver.protocol.SQLDataSerialization;
60 import org.objectweb.cjdbc.driver.protocol.TypeTag;
61
62 /**
63  * This class implements the communication protocol to the Controller.
64  * <p>
65  * Connection.java was inspired from the PostgreSQL JDBC driver by Peter T.
66  * Mount.
67  *
68  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
69  * @author <a HREF="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
70  * @author <a HREF="mailto:vadim@kase.kz">Vadim Kassin </a>
71  * @author <a HREF="mailto:duncan@mightybot.com">Duncan Smith </a>
72  * @author <a HREF="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
73  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
74  * @author <a HREF="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
75  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
76  * </a>
77  * @version 2.0
78  */

79 public class Connection implements java.sql.Connection JavaDoc
80 {
81   /** Does the controller wants SQL templates of PreparedStatements? */
82   protected boolean controllerNeedsSqlSkeleton = false;
83
84   /** Status of the connection. */
85   protected boolean isClosed = false;
86
87   protected String JavaDoc escapeChar = "\'";
88
89   /** C-JDBC controller we are connected to */
90   protected ControllerInfo controllerInfo = null;
91
92   // ConnectionClosingThread
93
/** Driver that created us. */
94   protected Driver driver = null;
95
96   /** Connection with the controller. */
97   protected Socket JavaDoc socket;
98   /** Socket input stream. */
99   protected CJDBCInputStream socketInput;
100   /** Socket output stream. */
101   protected CJDBCOutputStream socketOutput;
102
103   // used by Statement (and maybe also by some others _below_)
104
static final String JavaDoc LINE_SEPARATOR = System
105                                                                       .getProperty("line.separator");
106
107   // Member variables describing the state of the connection
108

109   /** Commit mode of the connection (<code>true</code>= automatic). */
110   protected boolean autoCommit = true;
111
112   /** Is the connection in read-only mode ? */
113   protected boolean readOnly = false;
114
115   /** Has a write request been executed in the current transaction? */
116   boolean writeExecutedInTransaction = false;
117
118   /** Default transaction isolation level if the user has not enforced one */
119   public static final int DEFAULT_TRANSACTION_ISOLATION_LEVEL = -1;
120   /** Current transaction isolation level. */
121   protected int isolationLevel = DEFAULT_TRANSACTION_ISOLATION_LEVEL;
122
123   /** transaction identifier. */
124   protected long transactionId = 0;
125
126   /** List of <code>Warnings</code> for this connection. */
127   protected SQLWarning JavaDoc firstWarning = null;
128
129   /** Meta-data of C-JDBC connections. */
130   protected DatabaseMetaData metaData = null;
131
132   /** Parsed URL to the database. */
133   private final CjdbcUrl cjdbcUrl;
134
135   /** Virtual database user used for this connection. */
136   protected String JavaDoc vdbUser = null;
137   protected String JavaDoc vdbPassword = null;
138
139   private AbstractBlobFilter blobFilter;
140   private boolean connectionPooling = true;
141
142   // Escape processing tuning
143
protected boolean escapeBackslash = true;
144   protected boolean escapeSingleQuote = true;
145
146   // Parsing Query values
147
protected boolean driverProcessed = true;
148
149   // PreparedStatement.setBoolean values
150
protected String JavaDoc preparedStatementBooleanTrue = "'1'";
151   protected String JavaDoc preparedStatementBooleanFalse = "'0'";
152
153   private boolean closeSocketOnGC = true;
154
155   /*****************************************************************************
156    * *************** * Constructor and get/set methods * ***********************
157    * ****************************************************************************
158    */

159
160   /**
161    * Creates a new <code>Connection</code> instance.
162    *
163    * @param driver calling driver
164    * @param socket connection with the controller
165    * @param in socket input stream
166    * @param out socket output stream
167    * @param cjdbcUrl C-JDBC URL of the database
168    * @param controller controller we are connected to
169    * @param userName user login
170    * @param password user password
171    * @throws AuthenticationException login error
172    * @throws IOException stream error
173    * @throws ProtocolException unexpected answer
174    */

175
176   public Connection(Driver driver, Socket JavaDoc socket, CJDBCInputStream in,
177       CJDBCOutputStream out, CjdbcUrl cjdbcUrl, ControllerInfo controller,
178       String JavaDoc userName, String JavaDoc password) throws AuthenticationException,
179       IOException JavaDoc, ProtocolException
180   {
181     this.driver = driver;
182     this.socket = socket;
183     this.socketInput = in;
184     this.socketOutput = out;
185     this.cjdbcUrl = cjdbcUrl;
186     this.controllerInfo = controller;
187     this.vdbUser = userName;
188     this.vdbPassword = password;
189
190     if (!in.readBoolean()) // failed
191
throw new AuthenticationException(in.readUTF());
192
193     this.controllerNeedsSqlSkeleton = in.readBoolean();
194     String JavaDoc sfilter = in.readUTF();
195     this.blobFilter = AbstractBlobFilter.getBlobFilterInstance(sfilter);
196
197     setUrlParametersOptionsOnConnection(cjdbcUrl);
198     if (cjdbcUrl.isDebugEnabled())
199       System.out.println("New connection:" + this.toString());
200   }
201
202   /**
203    * Set CjdbcUrl parameters options on connection.
204    *
205    * @param cjdbcUrl the C-JDBC URL to use
206    */

207   private void setUrlParametersOptionsOnConnection(CjdbcUrl cjdbcUrl)
208   {
209     HashMap JavaDoc cjdbcUrlParameters = cjdbcUrl.getParameters();
210
211     String JavaDoc booleanTrue = (String JavaDoc) cjdbcUrlParameters
212         .get(Driver.BOOLEAN_TRUE_PROPERTY);
213     if (booleanTrue != null)
214       setPreparedStatementBooleanTrue(booleanTrue);
215
216     String JavaDoc booleanFalse = (String JavaDoc) cjdbcUrlParameters
217         .get(Driver.BOOLEAN_FALSE_PROPERTY);
218     if (booleanFalse != null)
219       setPreparedStatementBooleanFalse(booleanFalse);
220
221     String JavaDoc escapeBaskslash = (String JavaDoc) cjdbcUrlParameters
222         .get(Driver.ESCAPE_BACKSLASH_PROPERTY);
223     if (escapeBaskslash != null)
224       setEscapeBackslash(new Boolean JavaDoc(escapeBaskslash).booleanValue());
225
226     String JavaDoc escapeQuote = (String JavaDoc) cjdbcUrlParameters
227         .get(Driver.ESCAPE_SINGLE_QUOTE_PROPERTY);
228     if (escapeQuote != null)
229       setEscapeSingleQuote(new Boolean JavaDoc(escapeQuote).booleanValue());
230
231     String JavaDoc escapeCharacter = (String JavaDoc) cjdbcUrlParameters
232         .get(Driver.ESCAPE_CHARACTER_PROPERTY);
233     if (escapeCharacter != null)
234       setEscapeChar(escapeCharacter);
235
236     String JavaDoc isDriverProcessed = (String JavaDoc) cjdbcUrlParameters
237         .get(Driver.DRIVER_PROCESSED_PROPERTY);
238     if (isDriverProcessed != null)
239       setDriverProcessed(Boolean.valueOf(isDriverProcessed).booleanValue());
240
241     // true if transparent connection pooling must be used
242
this.connectionPooling = !"false".equals(cjdbcUrlParameters
243         .get(Driver.CONNECTION_POOLING_PROPERTY));
244
245     if (cjdbcUrl.isDebugEnabled())
246     {
247       // Give a warning for unrecognized driver options
248
for (Iterator JavaDoc iter = cjdbcUrlParameters.entrySet().iterator(); iter
249           .hasNext();)
250       {
251         Map.Entry JavaDoc e = (Map.Entry JavaDoc) iter.next();
252         String JavaDoc param = (String JavaDoc) e.getKey();
253         if (!Driver.driverProperties.contains(param))
254           System.out.println("Unrecognized driver parameter: " + param + " = "
255               + (String JavaDoc) e.getValue());
256       }
257     }
258   }
259
260   /**
261    * @see java.lang.Object#finalize()
262    */

263   protected void finalize() throws Throwable JavaDoc
264   {
265     if (this.closeSocketOnGC)
266     {
267       Throwable JavaDoc t = null;
268       try
269       {
270         rollback();
271       }
272       catch (Exception JavaDoc e)
273       {
274         t = e;
275       }
276       try
277       {
278         close();
279       }
280       catch (Exception JavaDoc e)
281       {
282         t = e;
283       }
284
285       if (t != null)
286       {
287         throw t;
288       }
289
290     }
291     super.finalize();
292   }
293
294   /**
295    * Gets the C-JDBC URL of the database of the connection.
296    *
297    * @return value of url.
298    */

299   public String JavaDoc getUrl()
300   {
301     return cjdbcUrl.getUrl();
302   }
303
304   /**
305    * Gets the user name used to login to the database.
306    *
307    * @return login name
308    */

309   public String JavaDoc getUserName()
310   {
311     return vdbUser;
312   }
313
314   /**
315    * Gets the password used to login to the database.
316    *
317    * @return password
318    */

319   public String JavaDoc getPassword()
320   {
321     return vdbPassword;
322   }
323
324   /**
325    * Get the information about the controller we are connected to
326    *
327    * @return <code>ControllerInfo</code> object of the controller
328    */

329   public ControllerInfo getControllerInfo()
330   {
331     return controllerInfo;
332   }
333
334   //
335
// Connection interface methods
336
//
337

338   /**
339    * After this call, <code>getWarnings()</code> returns <code>null</code>
340    * until a new warning is reported for this connection.
341    */

342   public void clearWarnings()
343   {
344     firstWarning = null;
345   }
346
347   /**
348    * @see #close()
349    */

350   private void throwSQLExceptionIfClosed(String JavaDoc message)
351       throws DriverSQLException
352   {
353     if (isClosed)
354       throw new DriverSQLException(message);
355   }
356
357   /**
358    * @see #close()
359    */

360   private void throwSQLExceptionIfClosed() throws DriverSQLException
361   {
362     // default message
363
throwSQLExceptionIfClosed("Tried to operate on a closed Connection");
364   }
365
366   /**
367    * Releases the connection. In fact, the connection is marked to be released
368    * but will be effectively closed by the <code>ConnectionClosingThread</code>
369    * if the connection has not been reused before.
370    *
371    * @exception DriverSQLException if an error occurs
372    */

373   public void close() throws DriverSQLException
374   {
375     synchronized (this) // Wait until other methods/Commands are done
376
{
377       throwSQLExceptionIfClosed();
378       isClosed = true;
379       /*
380        * All JDBC entry points (methods) of this Connection have to
381        * throwSQLExceptionIfClosed(). Relaxed: at least every JDBC method _with
382        * some side-effect_ has to throwSQLExceptionIfClosed(). So now we are
383        * safe and can leave the lock, since they will fail anyway.
384        */

385     }
386
387     if (connectionPooling)
388     { // Try to pool the connection for later reuse
389
try
390       {
391         if (cjdbcUrl.isDebugEnabled())
392           System.out.println("Resetting connection and adding it to the pool");
393         autoCommit = true;
394         readOnly = false;
395         socketOutput.writeInt(Commands.Reset);
396         socketOutput.flush();
397       }
398       catch (IOException JavaDoc e)
399       {
400         throw new DriverSQLException("I/O Error while closing the connection\n"
401             + e.getLocalizedMessage(), e);
402       }
403
404       // only one (Connection) accessing the pool at a time
405
synchronized (driver.pendingConnectionClosing)
406       {
407         if (!driver.connectionClosingThreadisAlive)
408         { // First connection to close, start a new closing thread
409
if (cjdbcUrl.isDebugEnabled())
410             System.out.println("Starting a new connection closing thread");
411           ConnectionClosingThread t = new ConnectionClosingThread(driver);
412           t.start();
413         }
414         // Add to the list
415
driver.pendingConnectionClosing.add(this);
416       }
417     }
418     else
419     { // Close connection
420
try
421       {
422         driver = null; // probably useless since we use now
423
// throwSQLExceptionIfClosed(), but
424
// harmless anyway
425
if (socketOutput != null)
426         {
427           if (cjdbcUrl.isDebugEnabled())
428             System.out.println("Closing connection");
429           socketOutput.writeInt(Commands.Close);
430           socketOutput.flush();
431           if (socketInput != null)
432           { // Wait for the controller to receive the connection and close the
433
// stream. If we do not wait for the controller ack, the connection
434
// is closed on the controller before the closing is handled which
435
// results in an ugly warning message on the controller side. We are
436
// not in a hurry when closing the connection so let do the things
437
// nicely!
438
receiveBoolean();
439             socketInput.close();
440           }
441           socketOutput.close();
442         }
443
444         if (socket != null)
445           socket.close();
446       }
447       catch (Exception JavaDoc ignore)
448       {
449       }
450     }
451   }
452
453   /**
454    * Makes all changes made since the previous commit/rollback permanent and
455    * releases any database locks currently held by the <code>Connection</code>.
456    * This method should only be used when auto-commit has been disabled. (If
457    * <code>autoCommit</code>== <code>true</code>, then we throw a
458    * DriverSQLException).
459    *
460    * @exception DriverSQLException if a database access error occurs or the
461    * connection is in autocommit mode
462    * @see Connection#setAutoCommit(boolean)
463    */

464   public synchronized void commit() throws DriverSQLException
465   {
466     throwSQLExceptionIfClosed();
467     if (autoCommit)
468       throw new DriverSQLException(
469           "Trying to commit a connection in autocommit mode");
470
471     long firstTransactionId = this.transactionId;
472     try
473     {
474       socketOutput.writeInt(Commands.Commit);
475       socketOutput.flush();
476       // Commit is followed by a BEGIN
477
this.transactionId = receiveLong();
478       writeExecutedInTransaction = false;
479       if (cjdbcUrl.isDebugEnabled())
480         System.out.println("New transaction " + transactionId
481             + " has been started");
482     }
483     catch (SerializableException e)
484     {
485       throw new DriverSQLException(e);
486     }
487     catch (IOException JavaDoc e)
488     {
489       throw new DriverSQLException(
490           "I/O Error occured around commit of transaction '"
491               + firstTransactionId + "\n" + e.getLocalizedMessage(), e);
492     }
493   }
494
495   /**
496    * SQL statements without parameters are normally executed using
497    * <code>Statement</code> objects. If the same SQL statement is executed
498    * many times, it is more efficient to use a <code>PreparedStatement</code>.
499    * The <code>ResultSet</code> will be
500    * <code>TYPE_FORWARD_ONLY</cde>/<code>CONCUR_READ_ONLY</code>.
501    * *
502    * @return a new <code>Statement</code> object
503    * @exception DriverSQLException passed through from the constructor
504    */

505   public java.sql.Statement JavaDoc createStatement() throws DriverSQLException
506   {
507     throwSQLExceptionIfClosed();
508     return new Statement(this);
509   }
510
511   /**
512    * SQL statements without parameters are normally executed using
513    * <code>Statement</code> objects. If the same SQL statement is executed
514    * many times, it is more efficient to use a <code>PreparedStatement</code>.
515    *
516    * @param resultSetType resultSetType to use
517    * @param resultSetConcurrency resultSetConcurrency to use
518    * @return a new <code>Statement</code> object
519    * @exception SQLException passed through from the constructor
520    */

521   public java.sql.Statement JavaDoc createStatement(int resultSetType,
522       int resultSetConcurrency) throws SQLException JavaDoc
523   {
524     throwSQLExceptionIfClosed();
525     Statement s = new Statement(this);
526     s.setResultSetType(resultSetType);
527     s.setResultSetConcurrency(resultSetConcurrency);
528     return s;
529   }
530
531   /**
532    * Gets the current auto-commit state.
533    *
534    * @return current state of the auto-commit mode
535    * @exception DriverSQLException is connection is closed
536    * @see Connection#setAutoCommit
537    */

538   public boolean getAutoCommit() throws DriverSQLException
539   {
540     throwSQLExceptionIfClosed();
541     return this.autoCommit;
542   }
543
544   /**
545    * A connection's database is able to provide information describing its
546    * tables, its supported SQL grammar, its stored procedures, the capabilities
547    * of this connection, etc. This information is made available through a
548    * DatabaseMetaData object.
549    *
550    * @return a <code>DatabaseMetaData</code> object for this connection
551    * @exception DriverSQLException if connection is closed
552    */

553   public java.sql.DatabaseMetaData JavaDoc getMetaData() throws DriverSQLException
554   {
555     throwSQLExceptionIfClosed();
556     if (metaData == null)
557     {
558       metaData = new DatabaseMetaData(this);
559     }
560     return metaData;
561   }
562
563   /**
564    * Return current catalog name.
565    *
566    * @return name of the current <code>VirtualDatabase</code>
567    * @throws DriverSQLException if any error occurs
568    * @see Connection#getCatalog()
569    */

570   public synchronized String JavaDoc getCatalog() throws DriverSQLException
571   {
572     throwSQLExceptionIfClosed();
573     try
574     {
575       socketOutput.writeInt(Commands.ConnectionGetCatalog);
576       socketOutput.flush();
577
578       if (cjdbcUrl.isDebugEnabled())
579         System.out.println("Connection.getCatalog");
580
581       return receiveString();
582     }
583     catch (SerializableException e)
584     {
585       throw new DriverSQLException(e);
586     }
587     catch (IOException JavaDoc e)
588     {
589       throw wrapIOExceptionInDriverSQLException("getCatalog", e);
590     }
591   }
592
593   /**
594    * getCatalogs definition.
595    *
596    * @return instace of <code>ResultSet<code>
597    * @throws DriverSQLException if fails (include ANY exception that can be thrown in the code)
598    */

599   public synchronized ResultSet JavaDoc getCatalogs() throws DriverSQLException
600   {
601     throwSQLExceptionIfClosed();
602     String JavaDoc myName = "Connection.getCatalogs";
603     try
604     {
605       socketOutput.writeInt(Commands.ConnectionGetCatalogs);
606       socketOutput.flush();
607
608       if (cjdbcUrl.isDebugEnabled())
609         System.out.println(myName);
610
611       return receiveResultSet(myName);
612     }
613     catch (SerializableException e)
614     {
615       throw new DriverSQLException(e);
616     }
617     catch (IOException JavaDoc e)
618     {
619       throw wrapIOExceptionInDriverSQLException("getCatalogs", e);
620     }
621   }
622
623   protected synchronized java.sql.ResultSet JavaDoc getProcedures(String JavaDoc catalog,
624       String JavaDoc schemaPattern, String JavaDoc procedureNamePattern)
625       throws DriverSQLException
626   {
627     throwSQLExceptionIfClosed();
628     String JavaDoc myName = "Connection.getProcedures";
629     try
630     {
631       socketOutput.writeInt(Commands.DatabaseMetaDataGetProcedures);
632       socketOutput.writeUTF(catalog);
633       socketOutput.writeUTF(schemaPattern);
634       socketOutput.writeUTF(procedureNamePattern);
635       socketOutput.flush();
636
637       if (cjdbcUrl.isDebugEnabled())
638         System.out.println(myName + "(" + catalog + "," + schemaPattern + ","
639             + procedureNamePattern + ")");
640
641       return receiveResultSet(myName);
642     }
643     catch (SerializableException e)
644     {
645       throw new DriverSQLException(e);
646     }
647     catch (IOException JavaDoc e)
648     {
649       throw wrapIOExceptionInDriverSQLException("getProcedures", e);
650     }
651   }
652
653   protected synchronized java.sql.ResultSet JavaDoc getProcedureColumns(String JavaDoc catalog,
654       String JavaDoc schemaPattern, String JavaDoc procedureNamePattern,
655       String JavaDoc columnNamePattern) throws DriverSQLException
656   {
657     throwSQLExceptionIfClosed();
658     String JavaDoc myName = "Connection.getProcedureColumns";
659     try
660     {
661       socketOutput.writeInt(Commands.DatabaseMetaDataGetProcedureColumns);
662       socketOutput.writeUTF(catalog);
663       socketOutput.writeUTF(schemaPattern);
664       socketOutput.writeUTF(procedureNamePattern);
665       socketOutput.writeUTF(columnNamePattern);
666       socketOutput.flush();
667
668       if (cjdbcUrl.isDebugEnabled())
669         System.out.println(myName + "(" + catalog + "," + schemaPattern + ","
670             + procedureNamePattern + "," + columnNamePattern + ")");
671
672       return receiveResultSet(myName);
673     }
674     catch (SerializableException e)
675     {
676       throw new DriverSQLException(e);
677     }
678     catch (IOException JavaDoc e)
679     {
680       throw wrapIOExceptionInDriverSQLException("getProcedureColumns", e);
681     }
682   }
683
684   /**
685    * Gets this Connection's current transaction isolation mode. If the
686    * transaction isolation has not been set using setTransactionIsolation, this
687    * method will return by default
688    * java.sql.Connection.TRANSACTION_READ_UNCOMMITTED whatever transaction
689    * isolation is really used by the cluster nodes. If you want to enfore
690    * TRANSACTION_READ_UNCOMMITTED, you have to explicitely call
691    * setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED)
692    *
693    * @return the current <code>TRANSACTION_*</code> mode value
694    * @exception DriverSQLException if a database access error occurs
695    * @see #setTransactionIsolation(int)
696    */

697   public int getTransactionIsolation() throws DriverSQLException
698   {
699     throwSQLExceptionIfClosed();
700     // Warning, here we assume that if no transaction isolation is set the
701
// database will provide READ_UNCOMMITED.
702
if (isolationLevel == DEFAULT_TRANSACTION_ISOLATION_LEVEL)
703       return java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
704     return isolationLevel;
705   }
706
707   /**
708    * C-JDBC does NOT support type map.
709    *
710    * @return an exception
711    * @exception SQLException not supported
712    */

713   public java.util.Map JavaDoc getTypeMap() throws SQLException JavaDoc
714   {
715     throw new NotImplementedException("getTypeMap()");
716   }
717
718   /**
719    * The first warning reported by calls on this connection is returned. <B>
720    * Note: </B> Sebsequent warnings will be changed to this SQLWarning
721    *
722    * @return the first SQLWarning or null
723    */

724   public SQLWarning JavaDoc getWarnings()
725   {
726     return firstWarning;
727   }
728
729   /**
730    * Returns <code>true</code> if the connection has been closed by the user
731    * (but C-JDBC may leave it open underneath, unknown to the user).
732    *
733    * @return <code>true</code> if connection has never been opened or
734    * <code>close()</code> has been called
735    */

736   public boolean isClosed()
737   {
738     return isClosed;
739   }
740
741   /**
742    * Tests to see if the connection is in read only Mode. Note that we cannot
743    * really put the database in read only mode, but we pretend we can by
744    * returning the value of the <code>readOnly</code> flag.
745    *
746    * @return <code>true</code> if the connection is read only
747    */

748   public boolean isReadOnly()
749   {
750     return readOnly;
751   }
752
753   /**
754    * As we can't know for sure which database will execute this request (now or
755    * later), we can't translate it in the native query language of the
756    * underlying DBMS. Therefore the query is returned unchanged.
757    *
758    * @param query the query to change
759    * @return the original query
760    */

761   public String JavaDoc nativeSQL(String JavaDoc query)
762   {
763     return query;
764   }
765
766   /**
767    * Creates a CallableStatement that contains sql and produces a ResultSet that
768    * is TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY.
769    *
770    * @param sql SQL request
771    * @return nothing
772    * @exception SQLException not supported
773    */

774   public java.sql.CallableStatement JavaDoc prepareCall(String JavaDoc sql) throws SQLException JavaDoc
775   {
776     throwSQLExceptionIfClosed();
777     return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,
778         java.sql.ResultSet.CONCUR_READ_ONLY);
779   }
780
781   /**
782    * Stored procedure call are not yet supported by C-JDBC.
783    *
784    * @param sql a <code>String</code> value
785    * @param resultSetType an <code>int</code> value
786    * @param resultSetConcurrency an <code>int</code> value
787    * @return nothing
788    * @exception SQLException not supported
789    */

790   public java.sql.CallableStatement JavaDoc prepareCall(String JavaDoc sql, int resultSetType,
791       int resultSetConcurrency) throws SQLException JavaDoc
792   {
793     throwSQLExceptionIfClosed();
794     CallableStatement c = new CallableStatement(this, sql);
795     c.setResultSetType(resultSetType);
796     c.setResultSetConcurrency(resultSetConcurrency);
797     return c;
798   }
799
800   /**
801    * A SQL statement with or without <code>IN</code> parameters can be
802    * pre-compiled and stored in a PreparedStatement object. This object can then
803    * be used to efficiently execute this statement multiple times.
804    *
805    * @param sql a SQL statement that may contain one or more '?' IN * parameter
806    * placeholders
807    * @return a new <code>PreparedStatement</code> object containing the
808    * pre-compiled statement.
809    * @exception SQLException if a database access error occurs.
810    */

811   public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql)
812       throws SQLException JavaDoc
813   {
814     throwSQLExceptionIfClosed();
815     return new PreparedStatement(this, sql);
816   }
817
818   /**
819    * A SQL statement with or without IN parameters can be pre-compiled and
820    * stored in a <code>PreparedStatement</code> object. This object can then
821    * be used to efficiently execute this statement multiple times.
822    *
823    * @param sql a SQL statement that may contain one or more '?' IN
824    * @param resultSetType <code>ResultSetType</code> to use
825    * @param resultSetConcurrency <code>ResultSetConcurrency</code> to use
826    * @return a new <code>PreparedStatement</code> object
827    * @exception SQLException passed through from the constructor
828    */

829   public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql,
830       int resultSetType, int resultSetConcurrency) throws SQLException JavaDoc
831   {
832     throwSQLExceptionIfClosed();
833     PreparedStatement s = new PreparedStatement(this, sql);
834     s.setResultSetType(resultSetType);
835     s.setResultSetConcurrency(resultSetConcurrency);
836     return s;
837   }
838
839   /**
840    * Drops all changes made since the previous commit/rollback and releases any
841    * database locks currently held by this connection. If the connection was in
842    * autocommit mode, we throw a DriverSQLException.
843    *
844    * @exception DriverSQLException if a database access error occurs or the
845    * connection is in autocommit mode
846    * @see Connection#commit()
847    */

848   public synchronized void rollback() throws DriverSQLException
849   {
850     throwSQLExceptionIfClosed();
851     if (autoCommit)
852       throw new DriverSQLException(
853           "Trying to rollback a connection in autocommit mode");
854
855     long initialTransactionId = this.transactionId;
856     try
857     {
858       socketOutput.writeInt(Commands.Rollback);
859       socketOutput.flush();
860       // Rollback is followed by a BEGIN
861
this.transactionId = receiveLong();
862       writeExecutedInTransaction = false;
863
864       if (cjdbcUrl.isDebugEnabled())
865         System.out
866             .println("Transaction " + transactionId + " has been started");
867     }
868     catch (SerializableException e)
869     {
870       throw new DriverSQLException(e);
871     }
872     catch (IOException JavaDoc e)
873     {
874       throw new DriverSQLException(
875           "I/O Error occured around rollback of transaction '"
876               + initialTransactionId + "\n" + e.getLocalizedMessage(), e);
877     }
878   }
879
880   /**
881    * If a connection is in auto-commit mode, then all its SQL statements will be
882    * executed and committed as individual transactions. Otherwise, its SQL
883    * statements are grouped into transactions that are terminated by either
884    * {@link #commit()}or {@link #rollback()}. By default, new connections are
885    * in auto-commit mode. The commit occurs when the statement completes or the
886    * next execute occurs, whichever comes first. In the case of statements
887    * returning a <code>ResultSet</code>, the statement completes when the
888    * last row of the <code>ResultSet</code> has been retrieved or the
889    * <code>ResultSet</code> has been closed. In advanced cases, a single
890    * statement may return multiple results as well as output parameter values.
891    * Here the commit occurs when all results and output param values have been
892    * retrieved.
893    *
894    * @param autoCommit <code>true</code> enables auto-commit;
895    * <code>false</code> disables it
896    * @exception DriverSQLException if a database access error occurs
897    */

898   public synchronized void setAutoCommit(boolean autoCommit)
899       throws DriverSQLException
900   {
901     throwSQLExceptionIfClosed();
902     if (this.autoCommit == autoCommit)
903       return;
904
905     if (autoCommit)
906     { // enable autocommit
907
try
908       {
909         if (cjdbcUrl.isDebugEnabled())
910           System.out.println("Setting connection in autocommit mode");
911         socketOutput.writeInt(Commands.SetAutoCommit);
912         socketOutput.flush();
913
914         receiveBoolean();
915         writeExecutedInTransaction = false;
916         transactionId = 0;
917         this.autoCommit = true;
918         return;
919
920       }
921       catch (SerializableException se)
922       {
923         throw new DriverSQLException(se);
924       }
925       catch (IOException JavaDoc e)
926       {
927         throw new DriverSQLException(
928             "Error while trying to enable autocommit\n"
929                 + e.getLocalizedMessage(), e);
930       }
931     }
932     else
933     { // disable autocommit
934
try
935       {
936         socketOutput.writeInt(Commands.Begin);
937         socketOutput.flush();
938
939         transactionId = receiveLong();
940