KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > driver > Connection


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005-2006 Continuent, Inc.
6  * Contact: sequoia@continuent.org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * Initial developer(s): Emmanuel Cecchet.
21  * Contributor(s): Julie Marguerite, Guillaume Bort, Duncan Smith, Vadim Kassin,
22  * Nicolas Modrzyk, Jaco Swart, Jean-Bernard van Zuylen
23  * Completely refactored by Marc Herbert to remove the use of Java serialization.
24  */

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

80 public class Connection implements java.sql.Connection JavaDoc
81 {
82   /** Status of the connection. */
83   protected boolean isClosed = false;
84
85   protected String JavaDoc escapeChar;
86
87   /** Sequoia controller we are connected to */
88   protected ControllerInfo controllerInfo = null;
89
90   // ConnectionClosingThread
91
/** Driver that created us. */
92   protected Driver driver = null;
93
94   /** Connection with the controller. */
95   protected Socket JavaDoc socket;
96   /** Socket input stream. */
97   protected DriverBufferedInputStream socketInput;
98   /** Socket output stream. */
99   protected DriverBufferedOutputStream socketOutput;
100
101   /** @see org.continuent.sequoia.controller.core.ControllerConstants#SQL_SHORT_FORM_LENGTH */
102   static final int ABBREV_REQUEST_LENGTH = 40;
103
104   // used by Statement (and maybe also by some others _below_)
105
static final String JavaDoc LINE_SEPARATOR = System
106                                                                                .getProperty("line.separator");
107
108   // Member variables describing the state of the connection
109

110   /** Commit mode of the connection (<code>true</code>= automatic). */
111   protected boolean autoCommit = true;
112
113   /** Is the connection in read-only mode ? */
114   protected boolean readOnly = false;
115
116   /** Has a write request been executed in the current transaction? */
117   boolean writeExecutedInTransaction = false;
118
119   /** Default transaction isolation level if the user has not enforced one */
120   public static final int DEFAULT_TRANSACTION_ISOLATION_LEVEL = -1;
121
122   /** Current transaction isolation level. */
123   protected int isolationLevel = DEFAULT_TRANSACTION_ISOLATION_LEVEL;
124
125   /** transaction identifier. */
126   protected long transactionId = 0;
127
128   /** List of <code>Warnings</code> for this connection. */
129   protected SQLWarning JavaDoc firstWarning = null;
130
131   /** ResultSet holdability (JDBC 3) */
132   protected int holdability = HOLDABILITY_NOT_SET;
133   private static final int HOLDABILITY_NOT_SET = -1;
134
135   /** Meta-data of Sequoia connections. */
136   protected DatabaseMetaData metaData = null;
137
138   /** Parsed URL to the database. */
139   private final SequoiaUrl sequoiaUrl;
140
141   /** Virtual database user used for this connection. */
142   protected String JavaDoc vdbUser = null;
143   protected String JavaDoc vdbPassword = null;
144
145   private boolean connectionPooling;
146
147   // Escape processing tuning
148
protected boolean escapeBackslash;
149   protected boolean escapeSingleQuote;
150
151   // flag to check if a new transaction must be
152
// started before executing any statement
153
private boolean mustBeginTransaction = false;
154
155   // True if the connection must be persisted on all cluster backends even when
156
// autoCommit=true
157
private boolean persistentConnection;
158
159   // Persistent connection identifier if persistentConnection is true
160
private long persistentConnectionId;
161
162   // Do we want SQL Warnings ?
163
private boolean retrieveSQLWarnings = false;
164
165   // Do we force generated keys to be retrieved?
166
private boolean alwaysGetGeneratedKeys = false;
167
168   /*****************************************************************************
169    * *************** * Constructor and get/set methods * ***********************
170    * ****************************************************************************
171    */

172
173   /**
174    * Creates a new <code>Connection</code> instance.
175    *
176    * @param driver calling driver
177    * @param socket connection with the controller
178    * @param in socket input stream
179    * @param out socket output stream
180    * @param sequoiaUrl Sequoia URL of the database
181    * @param controller controller we are connected to
182    * @param userName user login
183    * @param password user password
184    * @throws AuthenticationException login error
185    * @throws IOException stream error
186    * @throws SQLException if the virtual database is not available on the
187    * controller
188    */

189
190   public Connection(Driver driver, Socket JavaDoc socket, DriverBufferedInputStream in,
191       DriverBufferedOutputStream out, SequoiaUrl sequoiaUrl,
192       ControllerInfo controller, String JavaDoc userName, String JavaDoc password)
193       throws AuthenticationException, IOException JavaDoc, SQLException JavaDoc
194   {
195     this.driver = driver;
196     this.socket = socket;
197     this.socketInput = in;
198     this.socketOutput = out;
199     this.sequoiaUrl = sequoiaUrl;
200     this.controllerInfo = controller;
201     this.vdbUser = userName;
202     this.vdbPassword = password;
203
204     escapeBackslash = driver.getEscapeBackslash();
205     escapeChar = driver.getEscapeChar();
206     escapeSingleQuote = driver.getEscapeSingleQuote();
207     connectionPooling = driver.getConnectionPooling();
208     persistentConnection = driver.getPersistentConnection();
209     retrieveSQLWarnings = driver.getRetrieveSQLWarnings();
210     alwaysGetGeneratedKeys = driver.getRetrieveGeneratedKeys();
211
212     // Is virtual database available?
213
if (!in.readBoolean()) // failed
214
throw new SQLException JavaDoc(in.readLongUTF());
215
216     // Is authentication successful?
217
if (!in.readBoolean()) // failed
218
throw new AuthenticationException(in.readLongUTF());
219
220     setUrlParametersOptionsOnConnection(sequoiaUrl);
221
222     out.writeLongUTF(LINE_SEPARATOR);
223     out.writeBoolean(persistentConnection);
224     out.flush();
225
226     if (persistentConnection)
227     {
228       if (in.readBoolean())
229         persistentConnectionId = in.readLong();
230       else
231         throw new AuthenticationException(
232             "No more persistent connections available for virtual database "
233                 + sequoiaUrl.getDatabaseName() + "[url=" + sequoiaUrl + "]");
234     }
235
236     out.writeBoolean(retrieveSQLWarnings);
237     out.flush();
238
239     if (sequoiaUrl.isDebugEnabled())
240       System.out.println("New connection:" + this.toString());
241   }
242
243   /**
244    * Set SequoiaUrl parameters options on connection.
245    *
246    * @param sequoiaUrl the Sequoia URL to use
247    */

248   private void setUrlParametersOptionsOnConnection(SequoiaUrl sequoiaUrl)
249   {
250     HashMap JavaDoc sequoiaUrlParameters = sequoiaUrl.getParameters();
251
252     String JavaDoc escapeBaskslash = (String JavaDoc) sequoiaUrlParameters
253         .get(Driver.ESCAPE_BACKSLASH_PROPERTY);
254     if (escapeBaskslash != null)
255       setEscapeBackslash(new Boolean JavaDoc(escapeBaskslash).booleanValue());
256
257     String JavaDoc escapeQuote = (String JavaDoc) sequoiaUrlParameters
258         .get(Driver.ESCAPE_SINGLE_QUOTE_PROPERTY);
259     if (escapeQuote != null)
260       setEscapeSingleQuote(new Boolean JavaDoc(escapeQuote).booleanValue());
261
262     String JavaDoc escapeCharacter = (String JavaDoc) sequoiaUrlParameters
263         .get(Driver.ESCAPE_CHARACTER_PROPERTY);
264     if (escapeCharacter != null)
265       setEscapeChar(escapeCharacter);
266
267     // true if transparent connection pooling must be used
268
String JavaDoc connPool = (String JavaDoc) sequoiaUrlParameters
269         .get(Driver.CONNECTION_POOLING_PROPERTY);
270     if (connPool != null)
271       this.connectionPooling = "true".equals(connPool);
272
273     String JavaDoc persistentConn = (String JavaDoc) sequoiaUrlParameters
274         .get(Driver.PERSISTENT_CONNECTION_PROPERTY);
275     if (persistentConn != null)
276       this.persistentConnection = "true".equals(persistentConn);
277
278     String JavaDoc retSQLWarns = (String JavaDoc) sequoiaUrlParameters
279         .get(Driver.RETRIEVE_SQL_WARNINGS_PROPERTY);
280     if (retSQLWarns != null)
281       this.retrieveSQLWarnings = "true".equals(retSQLWarns);
282
283     String JavaDoc retGeneratedKeys = (String JavaDoc) sequoiaUrlParameters
284         .get(Driver.ALWAYS_RETRIEVE_GENERATED_KEYS_PROPERTY);
285     if (retGeneratedKeys != null)
286       this.alwaysGetGeneratedKeys = "true".equals(retGeneratedKeys);
287
288     if (sequoiaUrl.isDebugEnabled())
289     {
290       // Give a warning for unrecognized driver options in the URL
291
// (only in the URL: unknown properties have been filtered out)
292
for (Iterator JavaDoc iter = sequoiaUrlParameters.entrySet().iterator(); iter
293           .hasNext();)
294       {
295         Map.Entry JavaDoc e = (Map.Entry JavaDoc) iter.next();
296         String JavaDoc param = (String JavaDoc) e.getKey();
297         if (!Driver.driverPropertiesNames.contains(param))
298           System.out.println("Unrecognized driver parameter: " + param + " = "
299               + (String JavaDoc) e.getValue());
300       }
301     }
302   }
303
304   /**
305    * Get the information about the controller we are connected to
306    *
307    * @return <code>ControllerInfo</code> object of the controller
308    */

309   public ControllerInfo getControllerInfo()
310   {
311     return controllerInfo;
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    * Gets the untouched String URL that was passed by the client application
326    *
327    * @return value of url.
328    */

329   public String JavaDoc getUrl()
330   {
331     return sequoiaUrl.getUrl();
332   }
333
334   /**
335    * Gets the parsed Sequoia URL, including merged properties
336    *
337    * @return the parsed Sequoia URL
338    */

339   SequoiaUrl getSequoiaUrl()
340   {
341     return sequoiaUrl;
342   }
343
344   /**
345    * Gets the user name used to login to the database.
346    *
347    * @return login name
348    */

349   public String JavaDoc getUserName()
350   {
351     return vdbUser;
352   }
353
354   /**
355    * Returns the escapeBackslash value.
356    *
357    * @return Returns the escapeBackslash.
358    */

359   public boolean isEscapeBackslash()
360   {
361     return escapeBackslash;
362   }
363
364   /**
365    * Sets the escapeBackslash value.
366    *
367    * @param escapeBackslash The escapeBackslash to set.
368    */

369   public void setEscapeBackslash(boolean escapeBackslash)
370   {
371     this.escapeBackslash = escapeBackslash;
372   }
373
374   /**
375    * Returns the escapeSingleQuote value.
376    *
377    * @return Returns the escapeSingleQuote.
378    */

379   public boolean isEscapeSingleQuote()
380   {
381     return escapeSingleQuote;
382   }
383
384   /**
385    * Sets the escapeSingleQuote value.
386    *
387    * @param escapeSingleQuote The escapeSingleQuote to set.
388    */

389   public void setEscapeSingleQuote(boolean escapeSingleQuote)
390   {
391     this.escapeSingleQuote = escapeSingleQuote;
392   }
393
394   /**
395    * Sets the escapeCharacter value
396    *
397    * @param escapeChar the escapeChar value to set
398    */

399   public void setEscapeChar(String JavaDoc escapeChar)
400   {
401     this.escapeChar = escapeChar;
402   }
403
404   /**
405    * @return Returns the escapeChar.
406    */

407   public String JavaDoc getEscapeChar()
408   {
409     return escapeChar;
410   }
411
412   /**
413    * Returns the connectionPooling value.
414    *
415    * @return Returns the connectionPooling.
416    */

417   public boolean isConnectionPooling()
418   {
419     return connectionPooling;
420   }
421
422   /**
423    * Sets the connectionPooling value.
424    *
425    * @param connectionPooling The connectionPooling to set.
426    */

427   public void setConnectionPooling(boolean connectionPooling)
428   {
429     this.connectionPooling = connectionPooling;
430   }
431
432   /**
433    * Returns the alwaysGetGeneratedKeys value.
434    *
435    * @return Returns the alwaysGetGeneratedKeys.
436    */

437   boolean isAlwaysGettingGeneratedKeys()
438   {
439     return alwaysGetGeneratedKeys;
440   }
441   
442   //
443
// java.sql.Connection implementation
444
//
445

446   /**
447    * After this call, <code>getWarnings()</code> returns <code>null</code>
448    * until a new call to getWarnings() on this connection.
449    *
450    * @exception SQLException if a database access error occurs
451    */

452   public void clearWarnings() throws SQLException JavaDoc
453   {
454     if (!persistentConnection || !retrieveSQLWarnings)
455       // nop
456
return;
457     if (isClosed)
458     {
459       // on a closed connection, just reset the warnings
460
// jdbc spec doesn't ask to throw SQLException
461
firstWarning = null;
462       return;
463     }
464
465     try
466     {
467       sendCommand(Commands.ConnectionClearWarnings);
468       socketOutput.writeLong(persistentConnectionId);
469       socketOutput.flush();
470       if (sequoiaUrl.isDebugEnabled())
471         System.out.println("Executing " + getCurrentMethodName());
472       // forget the ack, we just need to know if an exception occured
473
receiveBooleanOrException();
474     }
475     catch (SerializableException e)
476     {
477       throw new DriverSQLException(e);
478     }
479     catch (IOException JavaDoc e)
480     {
481       try
482       { // Connection failed, try to reconnect and re-send command
483
reconnect();
484         clearWarnings();
485       }
486       catch (DriverSQLException e1)
487       {
488         throw new DriverSQLException(
489             "Connection lost while clearWarnings() and automatic reconnect failed("
490                 + e1 + ")", e1);
491       }
492     }
493
494   }
495
496   /**
497    * Releases the connection. In fact, the connection is marked to be released
498    * but will be effectively closed by the <code>ConnectionClosingThread</code>
499    * if the connection has not been reused before.
500    *
501    * @exception DriverSQLException if an error occurs
502    */

503   public void close() throws DriverSQLException
504   {
505     synchronized (this) // Wait until other methods/Commands are done
506
{
507       // Spec says:
508
// Calling the method close on a Connection object that is already closed
509
// is a no-op.
510
if (isClosed)
511         return;
512       isClosed = true;
513       /*
514        * All JDBC entry points (methods) of this Connection have to
515        * throwSQLExceptionIfClosed(). Relaxed: at least every JDBC method _with
516        * some side-effect_ has to throwSQLExceptionIfClosed(). So now we are
517        * safe and can leave the lock, since they will fail anyway.
518        */

519     }
520
521     if (connectionPooling && !persistentConnection)
522     { // Try to pool the connection for later reuse
523
// Persistent connections are not pooled to free resources right away
524
if (sequoiaUrl.isDebugEnabled())
525         System.out.println("Resetting connection and adding it to the pool");
526       autoCommit = true;
527       mustBeginTransaction = false;
528       readOnly = false;
529       writeExecutedInTransaction = false;
530       isolationLevel = DEFAULT_TRANSACTION_ISOLATION_LEVEL;
531       try
532       {
533         sendCommand(Commands.Reset);
534         socketOutput.flush();
535         if (socketInput != null)
536         {
537           // Wait for the controller to receive the reset, in order to have
538
// an exception thrown if there are no more controllers
539
receiveBooleanOrException();
540         }
541       }
542       catch (Exception JavaDoc ignored)
543       {
544         // Try to reconnect to inform other controllers that we are reseting
545
// this connection. Do it only once to avoid endless loops
546
reconnect();
547         try
548         {
549           sendCommand(Commands.Reset);
550           socketOutput.flush();
551           if (socketInput != null)
552           {
553             // Wait for the controller to receive the reset, in order to have
554
// an exception thrown if there are no more controllers
555
receiveBooleanOrException();
556           }
557         }
558         catch (Exception JavaDoc e)
559         {
560           // Ok, no way to reset connection on the controller side, let's throw
561
// the exception
562
throw new DriverSQLException("Error while closing the connection\n"
563               + e.getLocalizedMessage(), e);
564         }
565       }
566
567       // only one (Connection) accessing the pool at a time
568
synchronized (driver.pendingConnectionClosing)
569       {
570         if (!driver.connectionClosingThreadisAlive)
571         { // First connection to close, start a new closing thread
572
if (sequoiaUrl.isDebugEnabled())
573             System.out.println("Starting a new connection closing thread");
574           ConnectionClosingThread t = new ConnectionClosingThread(driver);
575           t.start();
576         }
577         // Add to the list
578
driver.pendingConnectionClosing.add(this);
579       }
580     }
581     else
582     { // Close connection
583
try
584       {
585         // driver = null; // probably useless since we use now
586
// throwSQLExceptionIfClosed(), but
587
// harmless anyway
588
if (socketOutput != null)
589         {
590           if (sequoiaUrl.isDebugEnabled())
591             System.out.println("Closing connection");
592           sendCommand(Commands.Close);
593           socketOutput.flush();
594           if (socketInput != null)
595           { // Wait for the controller to receive the connection and close the
596
// stream. If we do not wait for the controller ack, the connection
597
// is closed on the controller before the closing is handled which
598
// results in an ugly warning message on the controller side. We are
599
// not in a hurry when closing the connection so let do the things
600
// nicely!
601
receiveBooleanOrException();
602             socketInput.close();
603           }
604           socketOutput.close();
605         }
606
607       }
608       catch (Exception JavaDoc ignore)
609       {
610         // we attempt to reconnect to another controller:
611
// since the connection was persistent, controllers
612
// must be informed of the close operation so that
613
// they can clean up their resources properly
614
reconnect();
615         close();
616       }
617     }
618   }
619
620   /**
621    * Makes all changes made since the previous commit/rollback permanent and
622    * releases any database locks currently held by the <code>Connection</code>.
623    * This method should only be used when auto-commit has been disabled. (If
624    * <code>autoCommit</code>== <code>true</code>, then we throw a
625    * DriverSQLException).
626    *
627    * @exception DriverSQLException if a database access error occurs or the
628    * connection is in autocommit mode
629    * @see Connection#setAutoCommit(boolean)
630    */

631   public synchronized void commit() throws DriverSQLException
632   {
633     throwSQLExceptionIfClosed();
634     if (autoCommit)
635     {
636       if (isCommitInAutoCommitAllowed())
637       {
638         return; // nothing to do
639
}
640       else
641       {
642         throw new DriverSQLException(
643             "Trying to commit a connection in autocommit mode");
644       }
645     }
646     // Check if we are not committing an empty transaction (not started yet)
647
if (mustBeginTransaction)
648       return;
649
650     doCommit();
651   }
652
653   private void doCommit() throws DriverSQLException
654   {
655     try
656     {
657       sendCommand(Commands.Commit);
658       socketOutput.flush();
659
660       // Commit acknowledgement
661
long acknowledgedTransactionId = receiveLongOrException();
662       // sanity check
663
if (acknowledgedTransactionId != transactionId)
664       {
665         throw new DriverSQLException(
666             "Protocol error during commit (acknowledge transaction ID = "
667                 + acknowledgedTransactionId + ", expected transaction ID = "
668                 + transactionId + ")");
669       }
670       mustBeginTransaction = true; // lazy begin
671
writeExecutedInTransaction = false;
672     }
673     catch (SerializableException e)
674     {
675       throw new DriverSQLException(e);
676     }
677     catch (IOException JavaDoc e)
678     { // Connection failed, try to reconnect and re-exec the commit
679
try
680       {
681         // this should resend transactionId (among others)
682
reconnect();
683
684         // get an ack
685
long acknowledgedTransactionId = retrieveCommitResult();
686         // sanity check
687
if (acknowledgedTransactionId != transactionId)
688         {
689           throw new DriverSQLException(
690               "Protocol error during commit (acknowledge transaction ID = "
691                   + acknowledgedTransactionId + ", expected transaction ID = "
692                   + transactionId + ")");
693         }
694         mustBeginTransaction = true;
695         writeExecutedInTransaction = false;
696
697         // The controller will automatically redo the commit if it was not done
698
// earlier so we can safely return here, this is a success.
699
return;
700       }
701       catch (DriverSQLException e1)
702       {
703         throw new DriverSQLException(
704             "Connection lost during commit of transaction '" + transactionId
705
706             + "' and automatic reconnect failed(" + e1 + ")", e1);
707       }
708     }
709   }
710
711   /**
712    * Determines whether or not commit should be allowed when autocommit is
713    * enabled.
714    *
715    * @return true when commit is allowed with autocommit
716    */

717   private boolean isCommitInAutoCommitAllowed()
718   {
719     String JavaDoc allowed = (String JavaDoc) sequoiaUrl.getParameters().get(
720         Driver.ALLOW_COMMIT_WTIH_AUTOCOMMIT_PROPERTY);
721
722     return allowed != null && allowed.toLowerCase().equals("true");
723   }
724
725   /**
726    * SQL statements without parameters are normally executed using
727    * <code>Statement</code> objects. If the same SQL statement is executed
728    * many times, it is more efficient to use a <code>PreparedStatement</code>.
729    * The <code>ResultSet</code> will be
730    * <code>TYPE_FORWARD_ONLY</cde>/<code>CONCUR_READ_ONLY</code>.
731    * *
732    * @return a new <code>Statement</code> object
733    * @exception DriverSQLException passed through from the constructor
734    */

735   public java.sql.Statement JavaDoc createStatement() throws DriverSQLException
736   {
737     throwSQLExceptionIfClosed();
738     return new Statement(this, driver);
739   }
740
741   /**
742    * SQL statements without parameters are normally executed using
743    * <code>Statement</code> objects. If the same SQL statement is executed
744    * many times, it is more efficient to use a <code>PreparedStatement</code>.
745    *
746    * @param resultSetType resultSetType to use
747    * @param resultSetConcurrency resultSetConcurrency to use
748    * @return a new <code>Statement</code> object
749    * @exception SQLException passed through from the constructor
750    */

751   public java.sql.Statement JavaDoc createStatement(int resultSetType,
752       int resultSetConcurrency) throws SQLException JavaDoc
753   {
754     throwSQLExceptionIfClosed();
755     Statement s = new Statement(this, driver);
756     s.setResultSetType(resultSetType);
757     s.setResultSetConcurrency(resultSetConcurrency);
758     return s;
759   }
760
761   /**
762    * Creates a <code>Statement</code> object that will generate
763    * <code>ResultSet</code> objects with the given type, concurrency, and
764    * holdability.
765    * <p>
766    * This method is the same as the <code>createStatement</code> method above,
767    * but it allows the default result set type, concurrency, and holdability to
768    * be overridden.
769    *
770    * @param resultSetType one of the following <code>ResultSet</code>
771    * constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
772    * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
773    * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
774    * @param resultSetConcurrency one of the following <code>ResultSet</code>
775    * constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
776    * <code>ResultSet.CONCUR_UPDATABLE</code>
777    * @param resultSetHoldability one of the following <code>ResultSet</code>
778    * constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
779    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
780    * @return a new <code>Statement</code> object that will generate
781    * <code>ResultSet</code> objects with the given type, concurrency,
782    * and holdability
783    * @exception SQLException if a database access error occurs or the given
784    * parameters are not <code>ResultSet</code> constants
785    * indicating type, concurrency, and holdability
786    * @see ResultSet
787    * @since JDK 1.4
788    */

789   public java.sql.Statement JavaDoc createStatement(int resultSetType,
790       int resultSetConcurrency, int resultSetHoldability) throws SQLException JavaDoc
791   {
792     throw new NotImplementedException(getCurrentMethodName());
793   }
794
795   /**
796    * Gets the current auto-commit state.
797    *
798    * @return current state of the auto-commit mode
799    * @exception DriverSQLException is connection is closed
800    * @see Connection#setAutoCommit
801    */

802   public boolean getAutoCommit() throws DriverSQLException
803   {
804     throwSQLExceptionIfClosed();
805     return this.autoCommit;
806   }
807
808   /**
809    * A connection's database is able to provide information describing its
810    * tables, its supported SQL grammar, its stored procedures, the capabilities
811    * of this connection, etc. This information is made available through a
812    * DatabaseMetaData object.
813    *
814    * @return a <code>DatabaseMetaData</code> object for this connection
815    * @exception DriverSQLException if connection is closed
816    */

817   public java.sql.DatabaseMetaData JavaDoc getMetaData() throws DriverSQLException
818   {
819     throwSQLExceptionIfClosed();
820     if (metaData == null)
821     {
822       metaData = new DatabaseMetaData(this);
823     }
824     return metaData;
825   }
826
827   /**
828    * Return current catalog name.
829    *
830    * @return name of the current <code>VirtualDatabase</code>
831    * @throws DriverSQLException if any error occurs
832    * @see Connection#getCatalog()
833    */

834   public synchronized String JavaDoc getCatalog() throws DriverSQLException
835   {
836     throwSQLExceptionIfClosed();
837     try
838     {
839       sendCommand(Commands.ConnectionGetCatalog);
840       socketOutput.flush();
841
842       if (sequoiaUrl.isDebugEnabled())
843         System.out.println("Executing " + getCurrentMethodName());
844
845       return receiveStringOrException();
846     }
847     catch (SerializableException e)
848     {
849       throw new DriverSQLException(e);
850     }
851     catch (IOException JavaDoc e)
852     {
853       try
854       {
855         reconnect();
856         return getCatalog();
857       }
858       catch (DriverSQLException e1)
859       {
860         throw new DriverSQLException("Connection lost while executing "
861             + getCurrentMethodName() + " and automatic reconnect failed ", e1);
862       }
863     }
864   }
865
866   /**
867    * getCatalogs definition.
868    *
869    * @return instace of <code>ResultSet<code>
870    * @throws DriverSQLException if fails (include ANY exception that can be thrown in the code)
871    */

872   public synchronized ResultSet JavaDoc getCatalogs() throws DriverSQLException
873   {
874     throwSQLExceptionIfClosed();
875     try
876     {
877       sendCommand(Commands.ConnectionGetCatalogs);
878       socketOutput.flush();
879
880       if (sequoiaUrl.isDebugEnabled())
881         System.out.println(getCurrentMethodName());
882
883       return receiveResultSet(getCurrentMethodName());
884     }
885     catch (SerializableException e)
886     {
887       throw new DriverSQLException(e);
888     }
889     catch (IOException JavaDoc e)
890     {
891       try
892       {
893         reconnect();
894         return getCatalogs();
895       }
896       catch (DriverSQLException e1)
897       {
898         throw new DriverSQLException(
899             "Connection lost and automatic reconnect failed while executing "
900                 + getCurrentMethodName(), e1);
901       }
902     }
903   }
904
905   /**
906    * Retrieves the current holdability of <code>ResultSet</code> objects
907    * created using this <code>Connection</code> object. If the value was not
908    * set using setHoldability(), the default value of the database is returned.
909    *
910    * @return the holdability, one of
911    * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
912    * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
913    * @throws SQLException if a database access occurs
914    * @see #setHoldability
915    * @see ResultSet
916    * @since JDK 1.4
917    */

918   public int getHoldability() throws SQLException JavaDoc
919   {
920     if (holdability == HOLDABILITY_NOT_SET)
921       holdability = getMetaData().getResultSetHoldability();
922     return holdability;
923   }
924
925   /**
926    * Gets this Connection's current transaction isolation mode. If the
927    * transaction isolation has not been set using setTransactionIsolation, this
928    * method will return by default
929    * java.sql.Connection.TRANSACTION_READ_UNCOMMITTED whatever transaction
930    * isolation is really used by the cluster nodes. If you want to enfore
931    * TRANSACTION_READ_UNCOMMITTED, you have to explicitely call
932    * setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED)
933    *
934    * @return the current <code>TRANSACTION_*</code> mode value
935    * @exception DriverSQLException if a database access error occurs
936    * @see #setTransactionIsolation(int)
937    */

938   public int getTransactionIsolation() throws DriverSQLException
939   {
940     throwSQLExceptionIfClosed();
941     // Warning, here we assume that if no transaction isolation is set the
942
// database will provide READ_UNCOMMITED.
943
if (isolationLevel == DEFAULT_TRANSACTION_ISOLATION_LEVEL)
944       return driver.getDefaultTransactionIsolationLevel();
945     return isolationLevel;
946   }
947
948   /**
949    * Sequoia does NOT support type map.
950    *
951    * @return an exception
952    * @exception SQLException not supported
953    */

954   public java.util.Map JavaDoc getTypeMap() throws SQLException JavaDoc
955   {
956     throw new NotImplementedException(getCurrentMethodName());
957   }
958
959   /**
960    * Returns the first warning reported by calls on this connection. Subsequent
961    * warnings will be chained to this SQLWarning<br>
962    * <B>Note: </B> If the 'persistent connections' option is set to false, this
963    * function will always return null.
964    *
965    * @return the first SQLWarning or null
966    * @exception DriverSQLException if a database access error occurs or this
967    * method is called on a closed connection
968    */

969   public SQLWarning JavaDoc getWarnings() throws DriverSQLException
970   {
971     throwSQLExceptionIfClosed();
972     if (!persistentConnection || !retrieveSQLWarnings)
973       return firstWarning;
974
975     try
976     {
977       sendCommand(Commands.ConnectionGetWarnings);
978       socketOutput.writeLong(persistentConnectionId);
979       socketOutput.flush();
980       if (sequoiaUrl.isDebugEnabled())
981         System.out.println("Executing " + getCurrentMethodName());
982       return receiveSQLWarnings();
983     }
984     catch (SerializableException e)
985     {
986       throw new DriverSQLException(e);
987     }
988     catch (IOException JavaDoc e)
989     {
990       try
991       { // Connection failed, try to reconnect and re-send command
992
reconnect();
993         return getWarnings();
994       }
995       catch (DriverSQLException e1)
996       {
997         throw new DriverSQLException(
998             "Connection lost while getting SQL Warnings and automatic reconnect failed("
999                 + e1 + ")", e1);
1000      }
1001    }
1002  }
1003
1004  /**
1005   * Returns <code>true</code> if the connection has been closed by the user
1006   * (but Sequoia may leave it open underneath, unknown to the user).
1007   *
1008   * @return <code>true</code> if connection has never been opened or
1009   * <code>close()</code> has been called
1010   */

1011  public boolean isClosed()
1012  {
1013    return isClosed;
1014  }
1015
1016  /**
1017   * Tests to see if the connection is in read only Mode. Note that we cannot
1018   * really put the database in read only mode, but we pretend we can by
1019   * returning the value of the <code>readOnly</code> flag.
1020   *
1021   * @return <code>true</code> if the connection is read only
1022   */

1023  public boolean isReadOnly()
1024  {
1025    return readOnly;
1026  }
1027
1028  /**
1029   * As we can't know for sure which database will execute this request (now or
1030   * later), we can't translate it in the native query language of the
1031   * underlying DBMS. Therefore the query is returned unchanged.
1032   *
1033   * @param query the query to change
1034   * @return the original query
1035   */

1036  public String JavaDoc nativeSQL(String JavaDoc query)
1037  {
1038    return query;
1039  }
1040
1041  /**
1042   * A SQL statement with or without <code>IN</code> parameters can be
1043   * pre-compiled and stored in a PreparedStatement object. This object can then
1044   * be used to efficiently execute this statement multiple times.
1045   *
1046   * @param sql a SQL statement that may contain one or more '?' IN * parameter
1047   * placeholders
1048   * @return a new <code>PreparedStatement</code> object containing the
1049   * pre-compiled statement.
1050   * @exception SQLException if a database access error occurs.
1051   */

1052  public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql)
1053      throws SQLException JavaDoc
1054  {
1055    throwSQLExceptionIfClosed();
1056    return new PreparedStatement(this, sql, driver);
1057  }
1058
1059  /**
1060   * Creates a default <code>PreparedStatement</code> object that has the
1061   * capability to retrieve auto-generated keys. The given constant tells the
1062   * driver whether it should make auto-generated keys available for retrieval.
1063   * This parameter is ignored if the SQL statement is not an
1064   * <code>INSERT</code> statement.
1065   * <p>
1066   * <b>Note: </b> This method is optimized for handling parametric SQL
1067   * statements that benefit from precompilation. If the driver supports
1068   * precompilation, the method <code>prepareStatement</code> will send the
1069   * statement to the database for precompilation. Some drivers may not support
1070   * precompilation. In this case, the statement may not be sent to the database
1071   * until the <code>PreparedStatement</code> object is executed. This has no
1072   * direct effect on users; however, it does affect which methods throw certain
1073   * SQLExceptions.
1074   * <p>
1075   * Result sets created using the returned <code>PreparedStatement</code>
1076   * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
1077   * concurrency level of <code>CONCUR_READ_ONLY</code>.
1078   *
1079   * @param sql an SQL statement that may contain one or more '?' IN parameter
1080   * placeholders
1081   * @param autoGeneratedKeys a flag indicating whether auto-generated keys
1082   * should be returned; one of
1083   * <code>Statement.RETURN_GENERATED_KEYS</code> or
1084   * <code>Statement.NO_GENERATED_KEYS</code>
1085   * @return a new <code>PreparedStatement</code> object, containing the
1086   * pre-compiled SQL statement, that will have the capability of
1087   * returning auto-generated keys
1088   * @exception SQLException if a database access error occurs or the given
1089   * parameter is not a <code>Statement</code> constant
1090   * indicating whether auto-generated keys should be returned
1091   * @since JDK 1.4
1092   */

1093  public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql,
1094      int autoGeneratedKeys) throws SQLException JavaDoc
1095  {
1096    throwSQLExceptionIfClosed();
1097    PreparedStatement ps = new PreparedStatement(this, sql, driver,
1098        autoGeneratedKeys);
1099    return ps;
1100  }
1101
1102  /**
1103   * Creates a default <code>PreparedStatement</code> object capable of
1104   * returning the auto-generated keys designated by the given array. This array
1105   * contains the indexes of the columns in the target table that contain the
1106   * auto-generated keys that should be made available. This array is ignored if
1107   * the SQL statement is not an <code>INSERT</code> statement.
1108   * <p>
1109   * An SQL statement with or without IN parameters can be pre-compiled and
1110   * stored in a <code>PreparedStatement</code> object. This object can then
1111   * be used to efficiently execute this statement multiple times.
1112   * <p>
1113   * <b>Note: </b> This method is optimized for handling parametric SQL
1114   * statements that benefit from precompilation. If the driver supports
1115   * precompilation, the method <code>prepareStatement</code> will send the
1116   * statement to the database for precompilation. Some drivers may not support
1117   * precompilation. In this case, the statement may not be sent to the database
1118   * until the <code>PreparedStatement</code> object is executed. This has no
1119   * direct effect on users; however, it does affect which methods throw certain
1120   * SQLExceptions.
1121   * <p>
1122   * Result sets created using the returned <code>PreparedStatement</code>
1123   * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
1124   * concurrency level of <code>CONCUR_READ_ONLY</code>.
1125   *
1126   * @param sql an SQL statement that may contain one or more '?' IN parameter
1127   * placeholders
1128   * @param columnIndexes an array of column indexes indicating the columns that
1129   * should be returned from the inserted row or rows
1130   * @return a new <code>PreparedStatement</code> object, containing the
1131   * pre-compiled statement, that is capable of returning the
1132   * auto-generated keys designated by the given array of column indexes
1133   * @exception SQLException if a database access error occurs
1134   * @since JDK 1.4
1135   */

1136  public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql,
1137      int[] columnIndexes) throws SQLException JavaDoc
1138  {
1139    throwSQLExceptionIfClosed();
1140    PreparedStatement ps = new PreparedStatement(this, sql, driver,
1141        java.sql.Statement.RETURN_GENERATED_KEYS);
1142    return ps;
1143  }
1144
1145  /**
1146   * Creates a default <code>PreparedStatement</code> object capable of
1147   * returning the auto-generated keys designated by the given array. This array
1148   * contains the names of the columns in the target table that contain the
1149   * auto-generated keys that should be returned. This array is ignored if the
1150   * SQL statement is not an <code>INSERT</code> statement.
1151   * <p>
1152   * An SQL statement with or without IN parameters can be pre-compiled and
1153   * stored in a <code>PreparedStatement</code> object. This object can then
1154   * be used to efficiently execute this statement multiple times.
1155   * <p>
1156   * <b>Note: </b> This method is optimized for handling parametric SQL
1157   * statements that benefit from precompilation. If the driver supports
1158   * precompilation, the method <code>prepareStatement</code> will send the
1159   * statement to the database for precompilation. Some drivers may not support
1160   * precompilation. In this case, the statement may not be sent to the database
1161   * until the <code>PreparedStatement</code> object is executed. This has no
1162   * direct effect on users; however, it does affect which methods throw certain
1163   * <code>SQLExceptions</code>.
1164   * <p>
1165   * Result sets created using the returned <code>PreparedStatement</code>
1166   * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
1167   * concurrency level of <code>CONCUR_READ_ONLY</code>.
1168   *
1169   * @param sql an SQL statement that may contain one or more '?' IN parameter
1170   * placeholders
1171   * @param columnNames an array of column names indicating the columns that
1172   * should be returned from the inserted row or rows
1173   * @return a new <code>PreparedStatement</code> object, containing the
1174   * pre-compiled statement, that is capable of returning the
1175   * auto-generated keys designated by the given array of column names
1176   * @exception SQLException if a database access error occurs
1177   * @since JDK 1.4
1178   */

1179  public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql,
1180      String JavaDoc[] columnNames) throws SQLException JavaDoc
1181  {
1182    throwSQLExceptionIfClosed();
1183    PreparedStatement ps = new PreparedStatement(this, sql, driver,
1184        java.sql.Statement.RETURN_GENERATED_KEYS);
1185    return ps;
1186  }
1187
1188  /**
1189   * A SQL statement with or without IN parameters can be pre-compiled and
1190   * stored in a <code>PreparedStatement</code> object. This object can then
1191   * be used to efficiently execute this statement multiple times.
1192   *
1193   * @param sql a SQL statement that may contain one or more '?' IN
1194   * @param resultSetType <code>ResultSetType</code> to use
1195   * @param resultSetConcurrency <code>ResultSetConcurrency</code> to use
1196   * @return a new <code>PreparedStatement</code> object
1197   * @exception SQLException passed through from the constructor
1198   */

1199  public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql,
1200      int resultSetType, int resultSetConcurrency) throws SQLException JavaDoc
1201  {
1202    throwSQLExceptionIfClosed();
1203    PreparedStatement s = new PreparedStatement(this, sql, driver);
1204    s.setResultSetType(resultSetType);
1205    s.setResultSetConcurrency(resultSetConcurrency);
1206    return s;
1207  }
1208
1209  /**
1210   * Creates a <code>PreparedStatement</code> object that will generate
1211   * <code>ResultSet</code> objects with the given type, concurrency, and
1212   * holdability.
1213   * <p>
1214   * This method is the same as the <code>prepareStatement</code> method
1215   * above, but it allows the default result set type, concurrency, and
1216   * holdability to be overridden.
1217   *
1218   * @param sql a <code>String</code> object that is the SQL statement to be
1219   * sent to the database; may contain one or more ? IN parameters
1220   * @param resultSetType one of the following <code>ResultSet</code>
1221   * constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
1222   * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
1223   * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
1224   * @param resultSetConcurrency one of the following <code>ResultSet</code>
1225   * constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
1226   * <code>ResultSet.CONCUR_UPDATABLE</code>
1227   * @param resultSetHoldability one of the following <code>ResultSet</code>
1228   * constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1229   * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1230   * @return a new <code>PreparedStatement</code> object, containing the
1231   * pre-compiled SQL statement, that will generate
1232   * <code>ResultSet</code> objects with the given type, concurrency,
1233   * and holdability
1234   * @exception SQLException if a database access error occurs or the given
1235   * parameters are not <code>ResultSet</code> constants
1236   * indicating type, concurrency, and holdability
1237   * @see ResultSet
1238   * @since JDK 1.4
1239   */

1240  public java.sql.PreparedStatement JavaDoc prepareStatement(String JavaDoc sql,
1241      int resultSetType, int resultSetConcurrency, int resultSetHoldability)
1242      throws SQLException JavaDoc
1243  {
1244    throwSQLExceptionIfClosed();
1245    PreparedStatement ps = new PreparedStatement(this, sql, driver);
1246    ps.setResultSetType(resultSetType);
1247    ps.setResultSetConcurrency(resultSetConcurrency);
1248    setHoldability(resultSetHoldability);
1249    return ps;
1250  }
1251
1252  /**
1253   * Creates a CallableStatement that contains sql and produces a ResultSet that
1254   * is TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY.
1255   *
1256   * @param sql SQL request
1257   * @return a CallableStatement
1258   * @exception SQLException not supported
1259   */

1260  public java.sql.CallableStatement JavaDoc prepareCall(String JavaDoc sql) throws SQLException JavaDoc
1261  {
1262    throwSQLExceptionIfClosed();
1263    return prepareCall(sql, java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,
1264        java.sql.ResultSet.CONCUR_READ_ONLY);
1265  }
1266
1267  /**
1268   * @see java.sql.Connection#prepareCall(java.lang.String, int, int)
1269   */

1270  public java.sql.CallableStatement JavaDoc prepareCall(String JavaDoc sql, int resultSetType,
1271      int resultSetConcurrency) throws SQLException JavaDoc
1272  {
1273    throwSQLExceptionIfClosed();
1274    CallableStatement c = new CallableStatement(this, sql, driver);
1275    c.setResultSetType(resultSetType);
1276    c.setResultSetConcurrency(resultSetConcurrency);
1277    return c;
1278  }
1279
1280  /**
1281   * Creates a <code>CallableStatement</code> object that will generate
1282   * <code>ResultSet</code> objects with the given type and concurrency. This
1283   * method is the same as the <code>prepareCall</code> method above, but it
1284   * allows the default result set type, result set concurrency type and
1285   * holdability to be overridden.
1286   *
1287   * @param sql a <code>String</code> object that is the SQL statement to be
1288   * sent to the database; may contain on or more ? parameters
1289   * @param resultSetType one of the following <code>ResultSet</code>
1290   * constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
1291   * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
1292   * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
1293   * @param resultSetConcurrency one of the following <code>ResultSet</code>
1294   * constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
1295   * <code>ResultSet.CONCUR_UPDATABLE</code>
1296   * @param resultSetHoldability one of the following <code>ResultSet</code>
1297   * constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1298   * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1299   * @return a new <code>CallableStatement</code> object, containing the
1300   * pre-compiled SQL statement, that will generate
1301   * <code>ResultSet</code> objects with the given type, concurrency,
1302   * and holdability
1303   * @exception SQLException if a database access error occurs or the given
1304   * parameters are not <code>ResultSet</code> constants
1305   * indicating type, concurrency, and holdability
1306   * @see ResultSet
1307   * @since JDK 1.4
1308   */

1309  public java.sql.CallableStatement JavaDoc prepareCall(String JavaDoc sql, int resultSetType,
1310      int resultSetConcurrency, int resultSetHoldability) throws SQLException JavaDoc
1311  {
1312    throwSQLExceptionIfClosed();
1313    CallableStatement cs = new CallableStatement(this, sql, driver);
1314    cs.setResultSetType(resultSetType);
1315    cs.setResultSetConcurrency(resultSetConcurrency);
1316    setHoldability(resultSetHoldability);
1317    return cs;
1318  }
1319
1320  /**
1321   * Removes the given <code>Savepoint</code> object from the current
1322   * transaction. Any reference to the savepoint after it have been removed will
1323   * cause an <code>SQLException</code> to be thrown.
1324   *
1325   * @param savepoint the <code>Savepoint</code> object to be removed
1326   * @exception DriverSQLException if a database access error occurs or the
1327   * given <code>Savepoint</code> object is not a valid savepoint
1328   * in the current transaction
1329   * @since JDK 1.4
1330   */

1331  public void releaseSavepoint(Savepoint savepoint) throws DriverSQLException
1332  {
1333    throwSQLExceptionIfClosed();
1334    if (savepoint == null)
1335      throw new DriverSQLException("Savepoint cannot be null");
1336
1337    if (autoCommit)
1338      throw new DriverSQLException(
1339          "Trying to release a savepoint in autocommit mode");
1340
1341    if (driver == null)
1342      throw new DriverSQLException("No driver to release a savepoint");
1343
1344    try
1345    {
1346      sendCommand(Commands.ReleaseSavepoint);
1347      savepointOnStream(savepoint);
1348      socketOutput.flush();
1349
1350      this.receiveBooleanOrException();
1351    }
1352    catch (SerializableException e)
1353    {
1354      throw new DriverSQLException(e);
1355    }
1356    catch (IOException JavaDoc e)
1357    {
1358      try
1359      {
1360        // Connection failed, try to reconnect and release the savepoint again
1361
reconnect();
1362        boolean done = retrieveReleaseSavepoint(savepoint);
1363        if (!done)
1364        {
1365          releaseSavepoint(savepoint);
1366        }
1367      }
1368      catch (DriverSQLException e1)
1369      {
1370        throw new DriverSQLException(
1371            "Connection lost while releasing savepoint '" + savepoint
1372                + "' and automatic reconnect failed(" + e1 + ")", e1);
1373      }
1374    }
1375  }
1376
1377  /**
1378   * Drops all changes made since the previous commit/rollback and releases any
1379   * database locks currently held by this connection. If the connection was in
1380   * autocommit mode, we throw a DriverSQLException.
1381   *
1382   * @exception DriverSQLException if a database access error occurs or the
1383   * connection is in autocommit mode
1384   * @see Connection#commit()
1385   */

1386  public synchronized void rollback() throws DriverSQLException
1387  {
1388    throwSQLExceptionIfClosed();
1389    if (autoCommit)
1390      throw new DriverSQLException(
1391          "Trying to rollback a connection in autocommit mode");
1392
1393    // Check if we are not rollbacking an empty transaction (not started yet)
1394
if (mustBeginTransaction)
1395      return;
1396
1397    try
1398    {
1399      sendCommand(Commands.Rollback);
1400      socketOutput.flush();
1401
1402      // rollback acknowledgement
1403
long acknowledgedTransactionId = receiveLongOrException();
1404      if (acknowledgedTransactionId != transactionId)
1405      {
1406        throw new DriverSQLException(
1407            "Protocol error during rollback (acknowledge transaction ID = "
1408                + acknowledgedTransactionId + ", expected transaction ID = "
1409                + transactionId + ")");
1410      }
1411      mustBeginTransaction = true;
1412      writeExecutedInTransaction = false;
1413    }
1414    catch (SerializableException e)
1415    {
1416      throw new DriverSQLException(e);
1417    }
1418    catch (IOException JavaDoc e)
1419    { // Connection failed, try to reconnect and re-exec the rollback
1420
try
1421      {
1422        reconnect();
1423
1424        long acknowledgedTransactionId = retrieveRollbackResult();
1425        if (acknowledgedTransactionId != transactionId)
1426        {
1427          throw new DriverSQLException(
1428              "Protocol error during rollback failover (acknowledge transaction ID = "
1429                  + acknowledgedTransactionId + ", expected transaction ID = "
1430                  + transactionId + ")");
1431        }
1432        mustBeginTransaction = true;
1433
1434        // The controller will automatically redo the rollback if it was not
1435
// done earlier so we can safely return here, this is a success.
1436
return;
1437      }
1438      catch (DriverSQLException e1)
1439      {
1440        throw new DriverSQLException(
1441            "Connection lost during rollback of transaction '" + transactionId
1442
1443            + "' and automatic reconnect failed(" + e1 + ")", e1);
1444      }
1445    }
1446  }
1447
1448  /**
1449   * Undoes all changes made after the given <code>Savepoint</code> object was
1450   * set.
1451   * <p>
1452   * This method should be used only when auto-commit has been disabled.
1453   *
1454   * @param savepoint the <code>Savepoint</code> object to roll back to
1455   * @exception DriverSQLException if a database access error occurs, the
1456   * <code>Savepoint</code> object is no longer valid, or this
1457   * <code>Connection</code> object is currently in auto-commit
1458   * mode
1459   * @see Savepoint
1460   * @see #rollback()
1461   * @since JDK 1.4
1462   */

1463  public void rollback(Savepoint savepoint) throws DriverSQLException
1464  {
1465    throwSQLExceptionIfClosed();
1466    if (savepoint == null)
1467      throw new DriverSQLException("Savepoint cannot be null");
1468
1469    if (autoCommit)
1470      throw new DriverSQLException(
1471          "Trying to rollback to a savepoint in autocommit mode");
1472
1473    if (driver == null)
1474      throw new DriverSQLException("No driver to rollback to savepoint");
1475
1476    try
1477    {
1478      sendCommand(Commands.RollbackToSavepoint);
1479      savepointOnStream(savepoint);
1480      socketOutput.flush();
1481
1482      this.receiveBooleanOrException();
1483    }
1484    catch (SerializableException e)
1485    {
1486      throw new DriverSQLException(e);
1487    }
1488    catch (IOException JavaDoc e)
1489    {
1490      try
1491      {
1492        // Connection failed, try to reconnect and rollback again if checkpoint
1493
// still exists
1494
reconnect();
1495        boolean isCheckpointRemoved = retrieveReleaseSavepoint(savepoint);
1496        if (!isCheckpointRemoved)
1497          rollback(savepoint);
1498      }
1499      catch (DriverSQLException e1)
1500      {
1501        throw new DriverSQLException(
1502            "Connection lost while rollbacking to savepoint '" + savepoint
1503                + "' and automatic reconnect failed(" + e1 + ")", e1);
1504      }
1505    }
1506  }
1507
1508  private void begin() throws DriverSQLException, ProtocolException
1509  {
1510    try
1511    {
1512      sendCommand(Commands.Begin);
1513      socketOutput.flush();
1514
1515      transactionId = receiveLongOrException();
1516
1517      if (sequoiaUrl.isDebugEnabled())
1518        System.out
1519            .println("Transaction " + transactionId + " has been started");
1520    }
1521    catch (SerializableException e)
1522    {
1523      throw new DriverSQLException(e);
1524    }
1525    catch (IOException JavaDoc e)
1526    {
1527      // Connection failed, try to reconnect and re-exec the query
1528
if (sequoiaUrl.isInfoEnabled())
1529        System.out.println("I/O Error while trying to disable autocommit\n"
1530            + e.getLocalizedMessage());
1531      reconnect();
1532      begin();
1533    }
1534  }
1535
1536  /**
1537   * To keep track of active transactions, sequoia uses the old BEGIN modeless
1538   * model. Backend connections on the controller are always maintained/reset in
1539   * autocommit mode = true, except of course when in the middle of an active
1540   * transaction. So part of our job here is to translate the new ODBC/JDBC
1541   * autoCommit mode concept to the old BEGIN model.
1542   *
1543   * @see Commands#Begin
1544   * @see java.sql.Connection#setAutoCommit(boolean)
1545   * @param autoCommitArg <code>true</code> enables auto-commit;
1546   * <code>false</code> disables it
1547   * @exception DriverSQLException if a database access error occurs
1548   * @throws DriverIOException if an IO error occured with the controller
1549   */

1550  public synchronized void setAutoCommit(boolean autoCommitArg)
1551      throws DriverSQLException, DriverIOException
1552  {
1553    throwSQLExceptionIfClosed();
1554
1555    // Do nothing if already in the right state
1556
if (this.autoCommit == autoCommitArg)
1557      return;
1558
1559    // true -> false (send nothing, lazy begin)
1560
if (this.autoCommit)
1561    {
1562      this.autoCommit = false;
1563      this.mustBeginTransaction = true;
1564      return;
1565    }
1566
1567    // false -> true
1568
if (mustBeginTransaction)
1569    { // Transaction has NOT yet begun
1570
// Just cancel the (lazy, not yet done) begin
1571
mustBeginTransaction = false;
1572      this.autoCommit = true;
1573      return;
1574    }
1575    else
1576    {
1577      if (sequoiaUrl.isDebugEnabled())
1578        System.out.println("Setting connection in autocommit mode");
1579      doCommit();
1580      this.autoCommit = true;
1581    }
1582  }
1583
1584  /**
1585   * Change the current catalog
1586   *
1587   * @param catalog a <code>String</code> value
1588   * @exception SQLException if fails or if catalog name is invalid
1589   */

1590  public synchronized void setCatalog(String JavaDoc catalog) throws SQLException JavaDoc
1591  {
1592    throwSQLExceptionIfClosed();
1593    if (catalog == null)
1594      throw new DriverSQLException("Invalid Catalog");
1595    sequoiaUrl.setUrl(driver.changeDatabaseName(sequoiaUrl.getUrl(), catalog));
1596
1597    try
1598    {
1599      sendCommand(Commands.ConnectionSetCatalog);
1600      socketOutput.writeLongUTF(catalog);
1601      socketOutput.flush();
1602
1603      if (sequoiaUrl.isDebugEnabled())
1604        System.out.println("Executing " + getCurrentMethodName()
1605            + " with catalog '" + catalog + "'");
1606
1607      if (!receiveBooleanOrException())
1608        throw new DriverSQLException("Invalid Catalog " + catalog);
1609
1610    }
1611    catch (SerializableException e)
1612    {
1613      throw new DriverSQLException(e);
1614    }
1615    catch (IOException JavaDoc e)
1616    {
1617      try
1618      {
1619        // Connection failed, try to reconnect and re-set the catalog
1620
reconnect();
1621        setCatalog(catalog);
1622      }
1623      catch (DriverSQLException e1)
1624      {
1625        throw new DriverSQLException(
1626            "Connection lost while setting the catalog '" + catalog
1627                + "' and automatic reconnect failed(" + e1 + ")", e1);
1628      }
1629    }
1630  }
1631
1632  /**
1633   * Changes the holdability of <code>ResultSet</code> objects created using
1634   * this <code>Connection</code> object to the given holdability.
1635   *
1636   * @param holdability a <code>ResultSet</code> holdability constant; one of
1637   * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1638   * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1639   * @throws SQLException if a database access occurs, the given parameter is
1640   * not a <code>ResultSet</code> constant indicating holdability,
1641   * or the given holdability is not supported
1642   * @see #getHoldability
1643   * @see ResultSet
1644   * @since JDK 1.4
1645   */

1646  public void setHoldability(int holdability) throws SQLException JavaDoc
1647  {
1648    if ((holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT)
1649        && (holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT))
1650      throw new SQLException JavaDoc("Invalid holdaibility value " + holdability);
1651    this.holdability = holdability;
1652  }
1653
1654  /**
1655   * You can put a connection in read-only mode as a hint to enable database
1656   * optimizations
1657   *
1658   * @param readOnly <code>true</code> enables read-only mode;
1659   * <code>false</code> disables it
1660   * @exception DriverSQLException if a database access error occurs
1661   */

1662  public void setReadOnly(boolean readOnly) throws DriverSQLException
1663  {
1664    throwSQLExceptionIfClosed();
1665
1666    try
1667    {
1668      sendCommand(Commands.SetReadOnly);
1669      socketOutput.writeBoolean(readOnly);
1670      socketOutput.flush();
1671
1672      if (sequoiaUrl.isDebugEnabled())
1673        System.out.println("Setting connection to read-only=" + readOnly);
1674
1675      receiveBooleanOrException();
1676      // Success
1677
this.readOnly = readOnly;
1678      return;
1679
1680    }
1681    catch (SerializableException e)
1682    {
1683      throw new DriverSQLException(e);
1684    }
1685    catch (IOException JavaDoc ioe)
1686    {
1687      try
1688      {
1689        // Connection failed, try to reconnect and re-set the transaction
1690
// isolation level
1691
reconnect();
1692        setReadOnly(readOnly);
1693      }
1694      catch (DriverSQLException e1)
1695      {
1696        throw new DriverSQLException(
1697            "Connection lost while setting the connection to read-only="
1698                + readOnly + " and automatic reconnect failed(" + e1 + ")", e1);
1699      }
1700    }
1701  }
1702
1703  private static final int SAVEPOINT_NOT_SET = -1;
1704
1705  /**
1706   * Creates an unnamed savepoint in the current transaction and returns the new
1707   * <code>Savepoint</code> object that represents it.
1708   *
1709   * @return the new <code>Savepoint</code> object
1710   * @exception DriverSQLException if a database access error occurs or this
1711   * <code>Connection</code> object is currently in auto-commit
1712   * mode
1713   * @see Savepoint
1714   * @since JDK 1.4
1715   */

1716  public Savepoint setSavepoint() throws DriverSQLException
1717  {
1718    throwSQLExceptionIfClosed();
1719    beginTransactionIfNeeded();
1720    if (autoCommit)
1721      throw new DriverSQLException(
1722          "Trying to set a savepoint in autocommit mode");
1723
1724    if (driver == null)
1725      throw new DriverSQLException("No driver to set a savepoint");
1726
1727    int savepointId = SAVEPOINT_NOT_SET;
1728    try
1729    {
1730      sendCommand(Commands.SetUnnamedSavepoint);
1731      socketOutput.flush();
1732
1733      savepointId = receiveIntOrException();
1734      return new org.continuent.sequoia.driver.Savepoint(savepointId);
1735    }
1736    catch (SerializableException e)
1737    {
1738      throw new DriverSQLException(e);
1739    }
1740    catch (IOException JavaDoc ioe)
1741    {
1742      try
1743      {
1744        // Connection failed, try to reconnect and re-set the savepoint if it
1745
// was not set before the failure
1746
reconnect();
1747        org.continuent.sequoia.driver.Savepoint savepoint = new org.continuent.sequoia.driver.Savepoint(
1748            savepointId);
1749        boolean checkpointDoesNotExit = (savepointId == SAVEPOINT_NOT_SET)
1750            || retrieveReleaseSavepoint(savepoint);
1751        if (checkpointDoesNotExit)
1752          return this.setSavepoint(); // retry, did not work the first time
1753
else
1754          return savepoint; // ok, already set
1755
}
1756      catch (DriverSQLException e1)
1757      {
1758        throw new DriverSQLException(
1759            "Connection lost while setting an unnamed savepoint and automatic reconnect failed("
1760                + e1 + ")", e1);
1761      }
1762    }
1763  }
1764
1765  /**
1766   * Creates a savepoint with the given name in the current transaction and
1767   * returns the new <code>Savepoint</code> object that represents it.
1768   *
1769   * @param name a <code>String</code> containing the name of the savepoint
1770   * @return the new <code>Savepoint</code> object
1771   * @exception DriverSQLException if a database access error occurs or this
1772   * <code>Connection</code> object is currently in auto-commit
1773   * mode
1774   * @see Savepoint
1775   * @since JDK 1.4
1776   */

1777  public Savepoint setSavepoint(String JavaDoc name) throws DriverSQLException
1778  {
1779    throwSQLExceptionIfClosed();
1780    beginTransactionIfNeeded();
1781    if (name == null)
1782      throw new IllegalArgumentException JavaDoc("Savepoint name cannot be null");
1783
1784    if (autoCommit)
1785      throw new DriverSQLException(
1786          "Trying to set a savepoint in autocommit mode");
1787
1788    if (driver == null)
1789      throw new DriverSQLException("No driver to set a savepoint");
1790
1791    try
1792    {
1793      sendCommand(Commands.SetNamedSavepoint);
1794      socketOutput.writeLongUTF(name);
1795      socketOutput.flush();
1796
1797      this.receiveBooleanOrException();
1798      return new org.continuent.sequoia.driver.Savepoint(name);
1799    }
1800    catch (SerializableException se)
1801    {
1802      throw new DriverSQLException(se);
1803    }
1804    catch (IOException JavaDoc e)
1805    {
1806      try
1807      {
1808        // Connection failed, try to reconnect and re-set the savepoint if it
1809
// was not set before the failure
1810
reconnect();
1811        org.continuent.sequoia.driver.Savepoint savepoint = new org.continuent.sequoia.driver.Savepoint(
1812            name);
1813        boolean checkpointDoesNotExit = retrieveReleaseSavepoint(savepoint);
1814        if (checkpointDoesNotExit)
1815          return setSavepoint(name);
1816        else
1817          return savepoint;
1818      }
1819      catch (DriverSQLException e1)
1820      {
1821        throw new DriverSQLException(
1822            "Connection lost while setting the savepoint '" + name
1823                + "' and automatic reconnect failed(" + e1 + ")", e1);
1824      }
1825    }
1826  }
1827
1828  /**
1829   * You can call this method to try to change the transaction isolation level
1830   * using one of the TRANSACTION_* values.
1831   * <p>
1832   * <B>Note: </B> this method cannot be called while in the middle of a
1833   * transaction. The JDBC spec says it should trigger a commit. We should
1834   * probably let the backend handle this, not trying to add our own complexity.
1835   *
1836   * @param level one of the TRANSACTION_* isolation values with * the exception
1837   * of TRANSACTION_NONE; some databases may * not support other values
1838   * @exception DriverSQLException if a database access error occurs
1839   * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
1840   */

1841  public synchronized void setTransactionIsolation(int level)
1842      throws DriverSQLException
1843  {
1844    throwSQLExceptionIfClosed();
1845    // Check if we are in a transaction or not. We have no trace on the driver
1846
// side if a read query has already been executed or not in the current
1847
// transaction (if any). We let the controller check for this (we only check
1848
// for writes here) as well as if the underlying databases support the
1849
// transaction isolation level. If this is not supported, the driver will
1850
// send back an exception.
1851
if ((autoCommit == false) && writeExecutedInTransaction)
1852      throw new DriverSQLException(
1853          getCurrentMethodName()
1854              + " cannot be called in a transaction that has executed write requests.");
1855
1856    if (level != isolationLevel)
1857    { // Only try to change if there is a new value
1858
if ((level == TRANSACTION_READ_COMMITTED)
1859          || (level == TRANSACTION_READ_UNCOMMITTED)
1860          || (level == TRANSACTION_REPEATABLE_READ)
1861          || (level == TRANSACTION_SERIALIZABLE))
1862      {
1863        try
1864        {
1865          sendCommand(Commands.SetTransactionIsolation);
1866          socketOutput.writeInt(level);
1867          socketOutput.flush();
1868
1869          if (sequoiaUrl.isDebugEnabled())
1870            System.out.println("Setting transaction isolation level to "
1871                + level);
1872
1873          receiveBooleanOrException();
1874          // Success
1875
isolationLevel = level;
1876          return;
1877
1878        }
1879        catch (SerializableException e)
1880        {
1881          throw new DriverSQLException(e);
1882        }
1883        catch (IOException JavaDoc ioe)
1884        {
1885          try
1886          {
1887            // Connection failed, try to reconnect and re-set the transaction
1888
// isolation level
1889
reconnect();
1890            setTransactionIsolation(level);
1891          }
1892          catch (DriverSQLException e1)
1893          {
1894            throw new DriverSQLException(
1895                "Connection lost while setting the transaction isolation level '"
1896                    + level + "' and automatic reconnect failed(" + e1 + ")",
1897                e1);
1898          }
1899        }
1900      }
1901      else
1902        throw new DriverSQLException("Invalid transaction isolation level "
1903            + level);
1904    } // we were already in that level; do nothing.
1905
}
1906
1907  /**
1908   * Sequoia does NOT support type map.
1909   *
1910   * @param map ignored
1911   * @exception SQLException not supported
1912   */

1913  public void setTypeMap(java.util.Map JavaDoc map) throws SQLException JavaDoc
1914  {
1915    throw new NotImplementedException(getCurrentMethodName());
1916  }
1917
1918  /*
1919   * Connection Sequoia internals
1920   */

1921
1922  /**
1923   * Begins a new transaction if needed (<code>mustBeginTransaction</code> is
1924   * set to <code>true</code>).
1925   *
1926   * @throws DriverSQLException if begin fails
1927   */

1928  private void beginTransactionIfNeeded() throws DriverSQLException
1929  {
1930    if (!mustBeginTransaction)
1931      return;
1932
1933    begin();
1934    this.mustBeginTransaction = false;
1935  }
1936
1937  /**
1938   * Fetch multiple results from a query executed with Statement.execute()
1939   *
1940   * @return the list of results
1941   */

1942  private List JavaDoc fetchMultipleResultsFromStream(String JavaDoc callerName)
1943      throws IOException JavaDoc, SerializableException, ProtocolException
1944  {
1945    boolean hasResult;
1946    int updateCount = 0;
1947    LinkedList JavaDoc results = new LinkedList JavaDoc();
1948    do
1949    {
1950      hasResult = receiveBooleanOrException();
1951      if (hasResult)
1952      {
1953        DriverResultSet rs = receiveResultSet(callerName);
1954        if (rs == null)
1955        {
1956          // This happens during transparent failover when the controller's
1957
// request cache hasn't found a result for a given request.
1958
return null;
1959        }
1960        else
1961        {
1962          results.addLast(rs);
1963        }
1964      }
1965      else
1966      {
1967        updateCount = receiveIntOrException();
1968        results.addLast(new Integer JavaDoc(updateCount));
1969      }
1970    }
1971    while (hasResult || updateCount != -1);
1972    return results;
1973  }
1974
1975  /**
1976   * Fetch named parameters from the stream.
1977   *
1978   * @return HashMap of <ParameterName,ParameterValue> or null
1979   * @throws ProtocolException if a protocol error occured
1980   * @throws IOException if an error with the socket occured
1981   * @throws SerializableException if a problem occured deserializing an object
1982   */

1983  private HashMap JavaDoc fetchNamedParameters() throws ProtocolException, IOException JavaDoc,
1984      SerializableException
1985  {
1986    if (sequoiaUrl.isDebugEnabled())
1987      System.out.println("Retrieving named parameters");
1988    String JavaDoc paramName = receiveStringOrException();
1989    if ("0".equals(paramName))
1990      return null;
1991    HashMap JavaDoc params = new HashMap JavaDoc();
1992    while (!"0".equals(paramName))
1993    {
1994      Object JavaDoc value = receiveObject();
1995      params.put(paramName, value);
1996      paramName = receiveStringOrException();
1997    }
1998    return params;
1999  }
2000
2001  /**
2002   * Fetch OUT parameters from the stream.
2003   *
2004   * @return HashMap of <ParameterName,ParameterValue> or null
2005   * @throws ProtocolException if a protocol error occured
2006   * @throws IOException if an error with the socket occured
2007   * @throws SerializableException if a problem occured deserializing an object
2008   */

2009  private HashMap JavaDoc fetchOutParameters() throws ProtocolException, IOException JavaDoc,
2010      SerializableException
2011  {
2012    if (sequoiaUrl.isDebugEnabled())
2013      System.out.println("Retrieving out parameters");
2014
2015    int index = receiveIntOrException();
2016    if (index == 0)
2017      return null;
2018    HashMap JavaDoc params = new HashMap JavaDoc();
2019    while (index != 0)
2020    {
2021      Object JavaDoc value = receiveObject();
2022      params.put(new Integer JavaDoc(index), value);
2023      index = receiveIntOrException();
2024    }
2025    return params;
2026  }
2027
2028  /**
2029   * Set the autocommit mode and read-only status on this request.
2030   *
2031   * @param request The request to set
2032   */

2033  private void setConnectionParametersOnRequest(Request request)
2034  {
2035    request.setIsAutoCommit(autoCommit);
2036  }
2037
2038  /**
2039   * Receive an object from the stream by fetching a tag first and then the
2040   * value from the proper serializer.
2041   *
2042   * @return the deserialized object (can be null)
2043   * @throws IOException if a socket error occurs
2044   * @throws ProtocolException if a protocol corruption is detected
2045   */

2046  private Object JavaDoc receiveObject() throws IOException JavaDoc, ProtocolException
2047  {
2048    TypeTag tag = new TypeTag(socketInput);
2049
2050    // Handle the null specific case
2051
if (TypeTag.JAVA_NULL.equals(tag))
2052      return null;
2053
2054    // We have a real object to de-serialize
2055
try
2056    {
2057      Serializer serializer = SQLDataSerialization.getSerializer(tag);
2058      return serializer.receiveFromStream(socketInput);
2059    }
2060    catch (IllegalArgumentException JavaDoc iae)
2061    {
2062      ProtocolException pe = new ProtocolException(
2063          "Protocol corruption: received unknown TypeTag " + tag
2064              + " when receiving object.");
2065      pe.initCause(iae);
2066      throw pe;
2067    }
2068  }
2069
2070  /**
2071   * Returns a DriverResultSet read from the stream or throws the
2072   * SerializableException that came instead
2073   *
2074   * @param callerName used for error messages. Is this really useful?
2075   * @return received ResultSet
2076   * @throws IOException stream or protocol error
2077   * @throws SerializableException received from the controller
2078   */

2079  private DriverResultSet receiveResultSet(String JavaDoc callerName)
2080      throws IOException JavaDoc, ProtocolException, SerializableException
2081  {
2082    TypeTag tag = new TypeTag(socketInput);
2083
2084    if (TypeTag.NULL_RESULTSET.equals(tag))
2085      return null;
2086
2087    if (TypeTag.RESULTSET.equals(tag))
2088    {
2089      DriverResultSet drs = new DriverResultSet(this);
2090      return drs;
2091    }
2092
2093    if (TypeTag.EXCEPTION.equals(tag))
2094      throw receiveException();
2095
2096    throw new ProtocolException(callerName
2097        + ": expected a resultset, received unexpected tag: " + tag);
2098  }
2099
2100  /**
2101   * Deserialize SQL warnings from the stream: converts BackendDriverException
2102   * to an SQLWarning chain
2103   *
2104   * @return the deserialized warning chain
2105   * @throws IOException stream error
2106   * @throws ProtocolException protocol error
2107   * @throws SerializableException
2108   */

2109  private SQLWarning JavaDoc receiveSQLWarnings() throws IOException JavaDoc,
2110      ProtocolException, SerializableException
2111  {
2112    if (!receiveBooleanOrException())
2113      // no warning
2114
return null;
2115    // Receive the warning as a BackendDriverException
2116
SerializableException e = receiveException();
2117    if (!(e instanceof BackendDriverException))
2118      throw new ProtocolException(
2119          "Unknown exception received instead of SQLWarning");
2120    return convertToSQLWarnings(e);
2121  }
2122
2123  /**
2124   * Deserialize an exception from the stream: converts explicit protocol typing
2125   * into java types.
2126   *
2127   * @return the deserialized exception read from the stream
2128   * @throws IOException stream error
2129   * @throws ProtocolException protocol error
2130   */

2131  private SerializableException receiveException() throws IOException JavaDoc,
2132      ProtocolException
2133  {
2134    TypeTag exceptionType = new TypeTag(socketInput);
2135
2136    if (TypeTag.BACKEND_EXCEPTION.equals(exceptionType))
2137      return new BackendDriverException(socketInput);
2138    if (TypeTag.CORE_EXCEPTION.equals(exceptionType))
2139      return new ControllerCoreException(socketInput);
2140
2141    throw new ProtocolException("received unknown exception type");
2142  }
2143
2144  /**
2145   * Returns a String read from the stream or throws the SerializableException
2146   * that came instead.
2147   *
2148   * @throws IOException stream or protocol error
2149   * @throws SerializableException coming from the controller
2150   * @throws ProtocolException protocol error
2151   */

2152  private String JavaDoc receiveStringOrException() throws IOException JavaDoc,
2153      SerializableException, ProtocolException
2154  {
2155    TypeTag tag = new TypeTag(socketInput);
2156    if (TypeTag.NOT_EXCEPTION.equals(tag))
2157    {
2158      String JavaDoc answer = socketInput.readLongUTF();
2159      return answer;
2160    }
2161
2162    throw receiveException();
2163  }
2164
2165  /**
2166   * Returns a boolean read from the stream or throws the SerializableException
2167   * that came instead.
2168   *
2169   * @throws IOException stream or protocol error
2170   * @throws SerializableException coming from the controller
2171   * @throws ProtocolException protocol error
2172   */

2173  private boolean receiveBooleanOrException() throws IOException JavaDoc,
2174      SerializableException, ProtocolException
2175  {
2176    TypeTag tag = new TypeTag(socketInput);
2177    if (TypeTag.NOT_EXCEPTION.equals(tag))
2178    {
2179      boolean answer = socketInput.readBoolean();
2180      return answer;
2181    }
2182
2183    throw receiveException();
2184  }
2185
2186  /**
2187   * Returns a int read from the stream or throws the SerializableException that
2188   * came instead.
2189   *
2190   * @throws IOException stream or protocol error
2191   * @throws SerializableException coming from the controller
2192   * @throws ProtocolException protocol error
2193   */

2194  private int receiveIntOrException() throws IOException JavaDoc,
2195      SerializableException, ProtocolException
2196  {
2197    TypeTag tag = new TypeTag(socketInput);
2198    if (TypeTag.NOT_EXCEPTION.equals(tag))
2199    {
2200      int answer = socketInput.readInt();
2201      return answer;
2202    }
2203
2204    throw receiveException();
2205  }
2206
2207  /**
2208   * Returns a long read from the stream or throws the SerializableException
2209   * that came instead.
2210   *
2211   * @throws IOException stream or protocol error
2212   * @throws SerializableException coming from the controller
2213   * @throws ProtocolException protocol error
2214   */

2215  private long receiveLongOrException() throws IOException JavaDoc,
2216      SerializableException, ProtocolException
2217  {
2218    TypeTag tag = new TypeTag(socketInput);
2219    if (TypeTag.NOT_EXCEPTION.equals(tag))
2220    {
2221      long answer = socketInput.readLong();
2222      return answer;
2223    }
2224
2225    throw receiveException();
2226  }
2227
2228  /**
2229   * Serialize a savepoint on the output stream by sending only the needed
2230   * parameters to reconstruct it on the controller
2231   *
2232   * @param savepoint the savepoint to send
2233   * @throws IOException if fails
2234   */

2235  private void savepointOnStream(Savepoint savepoint) throws IOException JavaDoc
2236  {
2237    writeExecutedInTransaction = true;
2238
2239    try
2240    {
2241      socketOutput.writeLongUTF(savepoint.getSavepointName());
2242      return;
2243    }
2244    catch (SQLException JavaDoc ignore)
2245    {
2246      // Ignoring because we are dealing with an un-named savepoint
2247
}
2248
2249    try
2250    {
2251      socketOutput.writeLongUTF(String.valueOf(savepoint.getSavepointId()));
2252      return;
2253    }
2254    catch (SQLException JavaDoc ignore)
2255    {
2256      // We should never get here
2257
}
2258  }
2259
2260  /**
2261   * Check if the given release savepoint has been successfully performed.
2262   *
2263   * @return true if the release savepoint has been successfully performed
2264   * @throws DriverSQLException if an error occured
2265   */

2266  private boolean retrieveReleaseSavepoint(Savepoint savepoint)
2267      throws DriverSQLException
2268  {
2269    try
2270    {
2271      sendCommand(Commands.RetrieveReleaseSavepoint);
2272      socketOutput.writeLongUTF(savepoint.getSavepointName());
2273      socketOutput.flush();
2274      return receiveBooleanOrException();
2275    }
2276    catch (Throwable JavaDoc e)
2277    {
2278      throw new DriverSQLException(getCurrentMethodName()
2279          + " failed on new controller (" + e + ")");
2280    }
2281  }
2282
2283  /**
2284   * Check if the given commit has been successfully performed.
2285   *
2286   * @return the transaction id if the commit has been successfully performed
2287   * @throws DriverSQLException if an error occured on the commit
2288   */

2289  private long retrieveCommitResult() throws DriverSQLException
2290  {
2291    try
2292    {
2293      sendCommand(Commands.RetrieveCommitResult);
2294      socketOutput.flush();
2295      return receiveLongOrException();
2296    }
2297    catch (Throwable JavaDoc e)
2298    {
2299      throw new DriverSQLException(getCurrentMethodName()
2300          + " failed on new controller (" + e + ")");
2301    }
2302  }
2303
2304  /**
2305   * Check if the given rollback has been successfully performed.
2306   *
2307   * @return the transaction id if the rollback has been successfully performed
2308   * @throws DriverSQLException if an error occured on the rollback
2309   */

2310  private long retrieveRollbackResult() throws DriverSQLException
2311  {
2312    try
2313    {
2314      sendCommand(Commands.RetrieveRollbackResult);
2315      socketOutput.flush();
2316      return receiveLongOrException();
2317    }
2318    catch (Throwable JavaDoc e)
2319    {
2320      throw new DriverSQLException(getCurrentMethodName()
2321          + " failed on new controller (" + e + ")");
2322    }
2323  }
2324
2325  /**
2326   * Check if the given query already executed or not on the controller we are
2327   * currently connected to.
2328   *
2329   * @param request the stored procedure to check
2330   * @return null if not found or a List composed of a
2331   * <code>java.sql.ResultSet</code> value, an <code>ArrayList</code>
2332   * of OUT parameters, and a <code>HashMap</code> of named parameters
2333   * result objects.
2334   * @throws DriverSQLException if an error occurs
2335   */

2336  private ResultAndWarnings retrieveExecuteQueryResultWithParameters(
2337      Request request) throws DriverSQLException
2338  {
2339    try
2340    {
2341      sendCommand(Commands.RetrieveExecuteQueryResultWithParameters);
2342      socketOutput.writeLong(request.getId());
2343      socketOutput.flush();
2344      SQLWarning JavaDoc sqlw = receiveSQLWarnings();
2345      DriverResultSet drs = receiveResultSet(getCurrentMethodName());
2346      if (drs == null)
2347        return null;
2348      List JavaDoc result = new ArrayList JavaDoc(3);
2349      result.add(drs);
2350      result.add(fetchOutParameters());
2351      result.add(fetchNamedParameters());
2352      return new ResultAndWarnings(result, sqlw);
2353    }
2354    catch (Throwable JavaDoc e)
2355    {
2356      throw new DriverSQLException(getCurrentMethodName()
2357          + " failed on new controller (" + e + ")");
2358    }
2359  }
2360
2361  /**
2362   * Check if the given query already executed or not on the controller we are
2363   * currently connected to.
2364   *
2365   * @param request the request to check
2366   * @return -1 if not found or a List composed of an <code>Integer</code>
2367   * (number of updated rows), an <code>ArrayList</code> of OUT
2368   * parameters, and a <code>HashMap</code> of named parameters result
2369   * objects.
2370   * @throws DriverSQLException if an error occurs
2371   */

2372  private ResultAndWarnings retrieveExecuteUpdateResultWithParameters(
2373      Request request) throws DriverSQLException
2374  {
2375    try
2376    {
2377      sendCommand(Commands.RetrieveExecuteUpdateResultWithParameters);
2378      socketOutput.writeLong(request.getId());
2379      socketOutput.flush();
2380      SQLWarning JavaDoc sqlw = receiveSQLWarnings();
2381      int updateCount = receiveIntOrException();
2382      if (updateCount == -1)
2383        return null; // No result found in failover
2384
List JavaDoc result = new ArrayList JavaDoc(3);
2385      result.add(new Integer JavaDoc(updateCount));
2386      result.add(fetchOutParameters());
2387      result.add(fetchNamedParameters());
2388      return new ResultAndWarnings(result, sqlw);
2389    }
2390    catch (Throwable JavaDoc e)
2391    {
2392      throw new DriverSQLException(getCurrentMethodName()
2393          + " failed on new controller (" + e + ")");
2394    }
2395  }
2396
2397  /**
2398   * Check if the given query already executed or not on the controller we are
2399   * currently connected to.
2400   *
2401   * @param request the request to check
2402   * @return null if not found or a List composed of 1. a <code>List</code> of
2403   * results <code>java.sql.ResultSet</code> value, 2. an
2404   * <code>ArrayList</code> of OUT parameters, and 3. a
2405   * <code>HashMap</code> of named parameters result objects.
2406   * @throws DriverSQLException if an error occurs
2407   */

2408  private ResultAndWarnings retrieveExecuteResultWithParameters(Request request)
2409      throws DriverSQLException
2410  {
2411    try
2412    {
2413      sendCommand(Commands.RetrieveExecuteResultWithParameters);
2414      socketOutput.writeLong(request.getId());
2415      socketOutput.flush();
2416      SQLWarning JavaDoc statementWarnings = receiveSQLWarnings();
2417      List JavaDoc results = fetchMultipleResultsFromStream(getCurrentMethodName());
2418      if (results == null)
2419        return null; // No result found in failover
2420
List JavaDoc result = new ArrayList JavaDoc(3);
2421      result.add(results);
2422      result.add(fetchOutParameters());
2423      result.add(fetchNamedParameters());
2424      return new ResultAndWarnings(result, statementWarnings);
2425    }
2426    catch (Throwable JavaDoc e)
2427    {
2428      throw new DriverSQLException(getCurrentMethodName()
2429          + " failed on new controller (" + e + ")");
2430    }
2431  }
2432
2433  /**
2434   * Check if the given query already executed or not on the controller we are
2435   * currently connected to.
2436   *
2437   * @param request the request to check
2438   * @return int the number of updated rows or -1 if not found
2439   * @throws DriverSQLException if an error occurs
2440   */

2441  private ResultAndWarnings retrieveExecuteUpdateResult(Request request)
2442      throws DriverSQLException
2443  {
2444    try
2445    {
2446      sendCommand(Commands.RetrieveExecuteUpdateResult);
2447      socketOutput.writeLong(request.getId());
2448      socketOutput.flush();
2449      SQLWarning JavaDoc sqlw = receiveSQLWarnings();
2450      int uc = receiveIntOrException();
2451      return new ResultAndWarnings(uc, sqlw);
2452    }
2453    catch (Throwable JavaDoc e)
2454    {
2455      throw new DriverSQLException(getCurrentMethodName()
2456          + " failed on new controller (" + e + ")");
2457    }
2458  }
2459
2460  /**
2461   * Check if the given query already executed or not on the controller we are
2462   * currently connected to.
2463   *
2464   * @param request the request to check
2465   * @return int the number of updated rows or -1 if not found
2466   * @throws DriverSQLException if an error occurs
2467   */

2468  private DriverGeneratedKeysResult retrieveExecuteUpdateWithKeysResult(
2469      Request request) throws DriverSQLException
2470  {
2471    try
2472    {
2473      sendCommand(Commands.RetrieveExecuteUpdateWithKeysResult);
2474      socketOutput.writeLong(request.getId());
2475      socketOutput.flush();
2476
2477      SQLWarning JavaDoc sqlw = receiveSQLWarnings();
2478      int updateCount = receiveIntOrException();
2479      if (updateCount == -1)
2480        return null;
2481
2482      // Fetch the ResultSet containing the autogenerated keys.
2483
TypeTag tag = new TypeTag(socketInput);
2484      if (TypeTag.RESULTSET.equals(tag))
2485      {
2486        DriverResultSet drs = new DriverResultSet(this);
2487        return new DriverGeneratedKeysResult(drs, updateCount, sqlw);
2488      }
2489
2490      if (TypeTag.NULL_RESULTSET.equals(tag))
2491        return new DriverGeneratedKeysResult(null, updateCount, sqlw);
2492
2493      // Error, unexpected answer
2494
throw new ProtocolException(getCurrentMethodName()
2495          + ": protocol corruption for request "
2496          + request.getSqlShortForm(ABBREV_REQUEST_LENGTH));
2497    }
2498    catch (Throwable JavaDoc e)
2499    {
2500      throw new DriverSQLException(getCurrentMethodName()
2501          + " failed on new controller (" + e + ")");
2502    }
2503  }
2504
2505  /**
2506   * Check if the given query already executed or not on the controller we are
2507   * currently connected to.
2508   *
2509   * @param request the request to check
2510   * @return a <code>List</code> of results or null if not found
2511   * @throws DriverSQLException if an error occurs
2512   */

2513  private ResultAndWarnings retrieveExecuteResult(Request request)
2514      throws DriverSQLException
2515  {
2516    try
2517    {
2518      sendCommand(Commands.RetrieveExecuteResult);
2519      socketOutput.writeLong(request.getId());
2520      socketOutput.flush();
2521      SQLWarning JavaDoc statementWarnings = receiveSQLWarnings();
2522      List JavaDoc resList = fetchMultipleResultsFromStream(getCurrentMethodName());
2523      return new ResultAndWarnings(resList, statementWarnings);
2524    }
2525    catch (Throwable JavaDoc e)
2526    {
2527      throw new DriverSQLException(getCurrentMethodName()
2528          + " failed on new controller (" + e + ")");
2529    }
2530  }
2531
2532  void reallyClose() throws IOException JavaDoc, DriverSQLException
2533  {
2534    sendCommand(Commands.Close);
2535  }
2536
2537  /**
2538   * Try first to reconnect to the same controller and if we don't succeed then
2539   * we notify the suspicion of failure if the current controller and we
2540   * reconnect to a controller chosen using the policy specified in the JDBC URL
2541   * of this connection.
2542   *
2543   * @throws DriverSQLException if an error occured during reconnect
2544   */

2545  private synchronized void reconnect() throws DriverSQLException
2546  {
2547    // Get rid of current connection
2548
try
2549    {
2550      this.socket.close();
2551    }
2552    catch (IOException JavaDoc ignore)
2553    {
2554    }
2555    try
2556    {
2557      this.socketInput.close();
2558    }
2559    catch (IOException JavaDoc ignore)
2560    {
2561    }
2562    try
2563    {
2564      this.socketOutput.close();
2565    }
2566    catch (IOException JavaDoc ignore)
2567    {
2568    }
2569    // only one (Connection) accessing the pool at a time
2570
synchronized (driver.pendingConnectionClosing)
2571    {
2572      if (driver.pendingConnectionClosing.remove(this))
2573        System.out.println("Warning! Closed call before reconnect");
2574    }
2575
2576    Connection newconn = null;
2577    // The SequoiaUrl does not carry the login/password info so we have to
2578
// re-create these properties to reconnect
2579
Properties JavaDoc properties = new Properties JavaDoc();
2580    properties.setProperty(Driver.USER_PROPERTY, vdbUser);
2581    properties.setProperty(Driver.PASSWORD_PROPERTY, vdbPassword);
2582
2583    AbstractControllerConnectPolicy controllerConnectPolicy = sequoiaUrl
2584        .getControllerConnectPolicy();
2585
2586    SequoiaUrl tempUrl = sequoiaUrl;
2587    if (persistentConnection)
2588    {
2589      /**
2590       * We do not want to create a persistent connection on the new connection,
2591       * because we will just close it during the restore operation. We need to
2592       * make a copy of sequoiaUrl, because it is shared with other connections.
2593       */

2594      Properties JavaDoc props = new Properties JavaDoc();
2595      for (Iterator JavaDoc iter = sequoiaUrl.getParameters().keySet().iterator(); iter
2596          .hasNext();)
2597      {
2598        String JavaDoc key = (String JavaDoc) iter.next();
2599        props.setProperty(key, (String JavaDoc) sequoiaUrl.getParameters().get(key));
2600      }
2601      try
2602      {
2603        tempUrl = new SequoiaUrl(driver, sequoiaUrl.getUrl(), props);
2604        tempUrl.getParameters().put(Driver.PERSISTENT_CONNECTION_PROPERTY,
2605            "false");
2606      }
2607      catch (SQLException JavaDoc e)
2608      {
2609        // if we could not get a new sequoiaUrl we will just use the original
2610
}
2611    }
2612
2613    controllerConnectPolicy.suspectControllerOfFailure(controllerInfo);
2614
2615    if (newconn == null)
2616    {
2617      // At this point, the current controller is down and we have to try a
2618
// new one that will be allocated by the policy specified in the URL.
2619
try
2620      {
2621        controllerInfo = controllerConnectPolicy.getController();
2622        if (sequoiaUrl.isDebugEnabled())
2623          System.out.println("Trying to reconnect to another controller: "
2624              + controllerInfo);
2625        newconn = (Connection) driver.connectToController(tempUrl,
2626            controllerInfo);
2627      }
2628      catch (AuthenticationException e)
2629      {
2630        // Should not happen, this probably mean an inconsistency in controller
2631
// configuration but safely ignore (see below)
2632
String JavaDoc msg = "Warning! Authentication exception received on connection retry, controller configuration might be inconsistent";
2633        if (sequoiaUrl.isInfoEnabled())
2634          System.out.println(msg);
2635        throw new DriverSQLException(msg, e);
2636      }
2637      catch (NoMoreControllerException nmc)
2638      {
2639        throw new DriverSQLException(nmc);
2640      }
2641      catch (SQLException JavaDoc e1)
2642      {
2643        // Impossible to connect to the new controller
2644
String JavaDoc msg = "Failed to reconnect to other controller: "
2645            + controllerInfo;
2646        if (sequoiaUrl.isDebugEnabled())
2647          System.out.println(msg);
2648        newconn = null;
2649        controllerConnectPolicy.suspectControllerOfFailure(controllerInfo);
2650        throw new DriverSQLException(msg, e1);
2651      }
2652    }
2653
2654    // newconn cannot be null here else an excepection would have been thrown
2655
// earlier.
2656

2657    // Success: let's use the new connection for ourselves
2658
this.socket = newconn.socket;
2659    this.socketInput = newconn.socketInput;
2660    this.socketOutput = newconn.socketOutput;
2661    this.controllerInfo = newconn.controllerInfo;
2662    this.isClosed = false;
2663    try
2664    {
2665      if (sequoiaUrl.isDebugEnabled())
2666        System.out.println("Restoring connection state on controller "
2667            + controllerInfo);
2668      sendCommand(Commands.RestoreConnectionState);
2669      socketOutput.writeBoolean(writeExecutedInTransaction);
2670      if (mustBeginTransaction)
2671      { // Say that we are in autoCommit, begin will be done later
2672
// Fixes SEQUOIA-522
2673
socketOutput.writeBoolean(true);
2674      }
2675      else
2676      {
2677        socketOutput.writeBoolean(autoCommit);
2678        if (!autoCommit)
2679          socketOutput.writeLong(transactionId);
2680      }
2681      socketOutput.writeBoolean(persistentConnection);
2682      if (persistentConnection)
2683        socketOutput.writeLong(persistentConnectionId);
2684      socketOutput.writeBoolean(retrieveSQLWarnings);
2685      socketOutput.flush();
2686      // Read ack. We won't do anything with it but reading this it is the only
2687
// way to dectect that the controller is down (see SEQUOIA-632)
2688
socketInput.readBoolean();
2689
2690      // Restore read-only state (not part of RestoreConnectionState command for
2691
// backward compatibility)
2692
setReadOnly(readOnly);
2693    }
2694    catch (IOException JavaDoc e)
2695    {
2696      reconnect();
2697    }
2698  }
2699
2700  /**
2701   * Before sending a command code, checks that the controller is
2702   * synchronized/ready to accept it. Then sends it.
2703   *
2704   * @param command to send
2705   * @throws IOException on socket error
2706   * @throws DriverSQLException on protocol corruption
2707   */

2708  private void sendCommand(int command) throws IOException JavaDoc, DriverSQLException
2709  {
2710    if (socketInput.readInt() != Commands.ControllerPrompt)
2711      throw new DriverSQLException(
2712          "Protocol corruption while trying to send command: " + command
2713              + ". Check the previous command");
2714    socketOutput.writeInt(Commands.CommandPrefix);
2715    socketOutput.writeInt(command);
2716  }
2717
2718  /**
2719   * @see #close()
2720   */

2721  private void throwSQLExceptionIfClosed(String JavaDoc message)
2722      throws DriverSQLException
2723  {
2724    if (isClosed)
2725      throw new DriverSQLException(message);
2726  }
2727
2728  /**
2729   * @see #close()
2730   */

2731  private void throwSQLExceptionIfClosed() throws DriverSQLException
2732  {
2733    // default message
2734
throwSQLExceptionIfClosed("Tried to operate on a closed Connection");
2735  }
2736
2737  private DriverSQLException wrapIOExceptionInDriverSQLException(
2738      String JavaDoc callerName, IOException JavaDoc ioe)
2739  {
2740    return new DriverSQLException("I/O Error on method " + callerName + "():\n"
2741        + ioe.getLocalizedMessage(), ioe);
2742  }
2743
2744  /**
2745   * Utility function to convert the given chain of backendException to a chain
2746   * of SQLWarnings
2747   *
2748   * @param toConvert exception chain to convert
2749   */

2750  protected SQLWarning JavaDoc convertToSQLWarnings(SerializableException toConvert)
2751  {
2752    if (toConvert == null)
2753      return null;
2754    SQLWarning JavaDoc sqlw = new SQLWarning JavaDoc(toConvert.getMessage(), toConvert
2755        .getSQLState(), toConvert.getErrorCode());
2756    Throwable JavaDoc t = toConvert.getCause();
2757    if (t instanceof SerializableException)
2758      sqlw.setNextWarning(convertToSQLWarnings((SerializableException) t));
2759    else if (sequoiaUrl.isDebugEnabled())
2760      System.out.println("Unexpected exception type " + t.getClass()
2761          + "while converting warning chain");
2762    return sqlw;
2763  }
2764
2765  /**
2766   * Performs a read request and return the reply.
2767   *
2768   * @param request the read request to execute
2769   * @return a <code>java.sql.ResultSet</code> value
2770   * @exception DriverSQLException if an error occurs
2771   */

2772  protected synchronized DriverResultSet statementExecuteQuery(
2773      RequestWithResultSetParameters request) throws DriverSQLException,
2774      NotImplementedException
2775  {
2776    throwSQLExceptionIfClosed("Closed connection cannot process request '"
2777        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2778    beginTransactionIfNeeded();
2779
2780    try
2781    {
2782      setConnectionParametersOnRequest(request);
2783      sendCommand(Commands.StatementExecuteQuery);
2784      request.sendToStream(socketOutput);
2785      socketOutput.flush();
2786      if (sequoiaUrl.isDebugEnabled())
2787        System.out.println("Executing " + getCurrentMethodName()
2788            + " with request " + request);
2789
2790      SQLWarning JavaDoc statementWarnings = receiveSQLWarnings();
2791      TypeTag tag = new TypeTag(socketInput);
2792
2793      // First case, we received our ResultSet, let's fetch it.
2794
if (TypeTag.RESULTSET.equals(tag))
2795      {
2796        try
2797        {
2798          DriverResultSet drs = new DriverResultSet(this);
2799          drs.setStatementWarnings(statementWarnings);
2800          return drs;
2801        }
2802        catch (ProtocolException e)
2803        {
2804          throw new DriverSQLException("Protocol corruption in "
2805              + getCurrentMethodName() + " with request "
2806              + request.getSqlShortForm(ABBREV_REQUEST_LENGTH), e);
2807        }
2808        catch (IOException JavaDoc e)
2809        { // Error while reading, retry
2810
if (sequoiaUrl.isInfoEnabled())
2811            System.out.println("IOException occured trying to reconnect ("
2812                + e.getLocalizedMessage() + ")");
2813          reconnect();
2814          return statementExecuteQuery(request);
2815        }
2816      }
2817
2818      if (TypeTag.NULL_RESULTSET.equals(tag))
2819        return null;
2820
2821      // From this point on, we had an exception
2822
if (TypeTag.EXCEPTION.equals(tag))
2823      {
2824        Exception JavaDoc recvEx = null;
2825        recvEx = receiveException();
2826        // dirty hack until cleanup
2827
if (recvEx instanceof ControllerCoreException)
2828          recvEx = ((ControllerCoreException) recvEx)
2829              .compatibilityWrapperHack();
2830
2831        if (recvEx instanceof NoMoreBackendException)
2832        {
2833          if (sequoiaUrl.isInfoEnabled())
2834            System.out.println("No more backend available on controller");
2835          throw new DriverSQLException(recvEx);
2836        }
2837        else if (recvEx instanceof IOException JavaDoc)
2838        {
2839          // We shouldn't have been able to receive this IOE because it means
2840
// that the socket died (at the controller side)
2841
throw new ProtocolException("Received exception of unexpected type ("
2842              + ((IOException JavaDoc) recvEx).getLocalizedMessage() + ")");
2843        }
2844        else if (recvEx instanceof BackendDriverException)
2845        {
2846          // TODO: temporary fix until DriverSQLException is fixed
2847
throw new DriverSQLException((SerializableException) recvEx);
2848        }
2849        else if (recvEx instanceof NotImplementedException)
2850        {
2851          // incredibly ugly.
2852
throw (NotImplementedException) recvEx;
2853        }
2854        else if (recvEx instanceof SQLException JavaDoc)
2855        {
2856          throw new DriverSQLException((SQLException JavaDoc) recvEx);
2857        }
2858      }
2859
2860      // Error, unexpected answer
2861
throw new ProtocolException("Protocol corruption in "
2862          + getCurrentMethodName() + " for request "
2863          + request.getSqlShortForm(ABBREV_REQUEST_LENGTH));
2864    }
2865    catch (SerializableException se)
2866    {
2867      throw new DriverSQLException(se);
2868    }
2869    catch (RuntimeException JavaDoc e)
2870    {
2871      e.printStackTrace();
2872      throw new DriverSQLException(getCurrentMethodName()
2873          + ": error occured while request '"
2874          + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
2875          + "' was processed by Sequoia Controller", e);
2876    }
2877    catch (IOException JavaDoc e)
2878    { // Connection failed, try to reconnect and re-exec the query
2879
try
2880      {
2881        if (sequoiaUrl.isInfoEnabled())
2882          System.out.println("IOException occured trying to reconnect ("
2883              + e.getMessage() + ")");
2884        reconnect();
2885        return statementExecuteQuery(request);
2886      }
2887      catch (DriverSQLException e1)
2888      {
2889        throw new DriverSQLException("Connection lost while executing "
2890            + getCurrentMethodName() + " with request '"
2891            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
2892            + "' and automatic reconnect failed (" + e1 + ")", e1);
2893      }
2894    }
2895  }
2896
2897  /**
2898   * Performs a write request and return the number of rows affected.
2899   *
2900   * @param request the write request to execute
2901   * @return number of rows affected
2902   * @exception DriverSQLException if an error occurs
2903   */

2904  protected synchronized ResultAndWarnings statementExecuteUpdate(
2905      Request request) throws DriverSQLException
2906  {
2907    throwSQLExceptionIfClosed("Closed connection cannot process request '"
2908        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2909    beginTransactionIfNeeded();
2910
2911    boolean requestIdIsSet = false;
2912    try
2913    {
2914      setConnectionParametersOnRequest(request);
2915      sendCommand(Commands.StatementExecuteUpdate);
2916      request.sendToStream(socketOutput);
2917      socketOutput.flush();
2918      if (sequoiaUrl.isDebugEnabled())
2919        System.out.println("Executing " + getCurrentMethodName()
2920            + " with request " + request);
2921
2922      request.setId(receiveLongOrException());
2923      requestIdIsSet = true;
2924      if (!autoCommit)
2925        writeExecutedInTransaction = true;
2926
2927      SQLWarning JavaDoc statementWarnings = receiveSQLWarnings();
2928      int uc = receiveIntOrException();
2929      return new ResultAndWarnings(uc, statementWarnings);
2930
2931    }
2932    catch (SerializableException se)
2933    {
2934      throw new DriverSQLException(se);
2935    }
2936    catch (IOException JavaDoc e)
2937    { // Connection failed, try to reconnect and re-exec the query
2938
try
2939      {
2940        reconnect();
2941        if (requestIdIsSet)
2942        { // Controller handled the query, check if it was executed
2943
ResultAndWarnings result = retrieveExecuteUpdateResult(request);
2944          if (result != null && result.getUpdateCount() != -1)
2945          {
2946            return result;
2947          }
2948        }
2949        // At this point the query failed before any controller succeeded in
2950
// executing the query
2951

2952        return statementExecuteUpdate(request);
2953      }
2954      catch (DriverSQLException e1)
2955      {
2956        throw new DriverSQLException("Connection lost while executing "
2957            + getCurrentMethodName() + " with request '"
2958            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
2959            + "' and automatic reconnect failed (" + e1 + ")", e1);
2960      }
2961    }
2962  }
2963
2964  /**
2965   * Call a request that returns a list of results.
2966   *
2967   * @param request the request to execute
2968   * @return a <code>List</code> of results
2969   * @throws DriverSQLException if an error occurs
2970   */

2971  protected synchronized ResultAndWarnings statementExecute(
2972      RequestWithResultSetParameters request) throws DriverSQLException
2973  {
2974    throwSQLExceptionIfClosed("Closed Connection cannot process request '"
2975        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2976    beginTransactionIfNeeded();
2977
2978    boolean requestIdIsSet = false;
2979    try
2980    {
2981      setConnectionParametersOnRequest(request);
2982      sendCommand(Commands.StatementExecute);
2983      request.sendToStream(socketOutput);
2984      socketOutput.flush();
2985      if (sequoiaUrl.isDebugEnabled())
2986        System.out.println("Executing " + getCurrentMethodName()
2987            + " with request" + request);
2988
2989      request.setId(receiveLongOrException());
2990      requestIdIsSet = true;
2991      if (!autoCommit)
2992        writeExecutedInTransaction = true;
2993
2994      SQLWarning JavaDoc sqlw = receiveSQLWarnings();
2995      List JavaDoc res = fetchMultipleResultsFromStream(getCurrentMethodName());
2996      return new ResultAndWarnings(res, sqlw);
2997    }
2998    catch (RuntimeException JavaDoc e)
2999    {
3000      throw new DriverSQLException(getCurrentMethodName()
3001          + ": Error occured while request '"
3002          + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3003          + "' was processed by Sequoia Controller", e);
3004    }
3005    catch (IOException JavaDoc e)
3006    { // Connection failed, try to reconnect and re-exec the query
3007
try
3008      {
3009        reconnect();
3010        if (requestIdIsSet)
3011        { // Controller handled the query, check if it was executed
3012
ResultAndWarnings rww = retrieveExecuteResult(request);
3013          if (rww != null && rww.getResultList() != null)
3014            return rww;
3015        }
3016        // At this point the query failed before any controller succeeded in
3017
// executing the query
3018

3019        return statementExecute(request);
3020      }
3021      catch (DriverSQLException e1)
3022      {
3023        throw new DriverSQLException("Connection lost while executing "
3024            + getCurrentMethodName() + " with request '"
3025            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3026            + "' and automatic reconnect failed (" + e1 + ")", e1);
3027      }
3028    }
3029    catch (SerializableException e)
3030    {
3031      throw new DriverSQLException(e);
3032    }
3033  }
3034
3035  /**
3036   * Performs a write request and returns the auto-generated keys
3037   *
3038   * @param request the write request to execute
3039   * @return auto generated keys
3040   * @exception DriverSQLException if an error occurs
3041   */

3042  protected synchronized DriverGeneratedKeysResult statementExecuteUpdateWithKeys(
3043      Request request) throws DriverSQLException
3044  {
3045    throwSQLExceptionIfClosed("Closed Connection cannot process request '"
3046        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
3047    beginTransactionIfNeeded();
3048
3049    boolean requestIdIsSet = false;
3050    try
3051    {
3052      setConnectionParametersOnRequest(request);
3053      sendCommand(Commands.StatementExecuteUpdateWithKeys);
3054      request.sendToStream(socketOutput);
3055      socketOutput.flush();
3056      if (sequoiaUrl.isDebugEnabled())
3057        System.out.println("Executing " + getCurrentMethodName()
3058            + " with request: " + request);
3059
3060      try
3061      {
3062        request.setId(receiveLongOrException());
3063        requestIdIsSet = true;
3064        if (!autoCommit)
3065          writeExecutedInTransaction = true;
3066
3067        // Receive the warnings
3068
SQLWarning JavaDoc sqlw = receiveSQLWarnings();
3069
3070        // Receive the update count or an exception
3071
int updateCount = receiveIntOrException();
3072
3073        // Fetch the ResultSet containing the autogenerated keys.
3074
TypeTag tag = new TypeTag(socketInput);
3075        if (TypeTag.RESULTSET.equals(tag))
3076        {
3077          try
3078          {
3079            DriverResultSet drs = new DriverResultSet(this);
3080            return new DriverGeneratedKeysResult(drs, updateCount, sqlw);
3081          }
3082          catch (ProtocolException e)
3083          {
3084            throw new DriverSQLException("Protocol corruption in "
3085                + getCurrentMethodName() + " with request "
3086                + request.getSqlShortForm(ABBREV_REQUEST_LENGTH), e);
3087          }
3088          catch (IOException JavaDoc e)
3089          { // Error while reading, retry
3090
if (sequoiaUrl.isInfoEnabled())
3091              System.out.println("IOException occured trying to reconnect ("
3092                  + e.getLocalizedMessage() + ")");
3093            reconnect();
3094            return statementExecuteUpdateWithKeys(request);
3095          }
3096        }
3097
3098        if (TypeTag.NULL_RESULTSET.equals(tag))
3099          return new DriverGeneratedKeysResult(null, updateCount, sqlw);
3100
3101        // Error, unexpected answer
3102
throw new ProtocolException("Protocol corruption in "
3103            + getCurrentMethodName() + " for request "
3104            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH));
3105      }
3106      catch (SerializableException e)
3107      {
3108        throw new DriverSQLException(e);
3109      }
3110    }
3111    catch (IOException JavaDoc e)
3112    { // Connection failed, try to reconnect and re-exec the query
3113
try
3114      {
3115        reconnect();
3116        if (requestIdIsSet)
3117        { // Controller handled the query, check if it was executed
3118
DriverGeneratedKeysResult result = retrieveExecuteUpdateWithKeysResult(request);
3119          if (result != null)
3120            return result;
3121        }
3122        // At this point the query failed before any controller succeeded in
3123
// executing the query
3124
return statementExecuteUpdateWithKeys(request);
3125      }
3126      catch (DriverSQLException e1)
3127      {
3128        throw new DriverSQLException("Connection lost while executing "
3129            + getCurrentMethodName() + " with request '"
3130            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3131            + "' and automatic reconnect failed (" + e1 + ")", e1);
3132      }
3133    }
3134  }
3135
3136  /**
3137   * Call a stored procedure (with IN/OUT and/or named parameters) that returns
3138   * a ResultSet.
3139   *
3140   * @param proc the stored procedure call
3141   * @return a List composed of a <code>java.sql.ResultSet</code> value, an
3142   * <code>ArrayList</code> of OUT parameters, and a
3143   * <code>HashMap</code> of named parameters result objects.
3144   * @exception DriverSQLException if an error occurs
3145   */

3146  protected synchronized ResultAndWarnings callableStatementExecuteQuery(
3147      RequestWithResultSetParameters proc) throws DriverSQLException
3148  {
3149    throwSQLExceptionIfClosed("Closed Connection cannot process request '"
3150        + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
3151    beginTransactionIfNeeded();
3152
3153    boolean procIdIsSet = false;
3154    try
3155    {
3156      setConnectionParametersOnRequest(proc);
3157      sendCommand(Commands.CallableStatementExecuteQueryWithParameters);
3158      proc.sendToStream(socketOutput);
3159      socketOutput.flush();
3160      if (sequoiaUrl.isDebugEnabled())
3161        System.out.println("Executing " + getCurrentMethodName()
3162            + " with procedure '" + proc + "'");
3163
3164      proc.setId(receiveLongOrException());
3165      procIdIsSet = true;
3166      if (!autoCommit)
3167        writeExecutedInTransaction = true;
3168
3169      if (sequoiaUrl.isDebugEnabled())
3170        System.out.println("Received unique id " + proc.getId()
3171            + " for procedure '" + proc + "'");
3172
3173      SQLWarning JavaDoc sqlw = receiveSQLWarnings();
3174
3175      Exception JavaDoc recvEx = null;
3176      TypeTag tag = new TypeTag(socketInput);
3177
3178      DriverResultSet drs = null;
3179
3180      /*
3181       * TODO: the code below is a complete mess. One reason is it's still half
3182       * legacy design from old protocol, half from the new procotol. It could
3183       * easily be made much simpler. We should use #receiveResultSet() TODO:
3184       * test NoMoreBackendException
3185       */

3186      if (!TypeTag.NULL_RESULTSET.equals(tag))
3187      {
3188        if (TypeTag.EXCEPTION.equals(tag))
3189        {
3190          recvEx = receiveException();
3191          // dirty hack until cleanup
3192
if (recvEx instanceof ControllerCoreException)
3193            recvEx = ((ControllerCoreException) recvEx)
3194                .compatibilityWrapperHack();
3195
3196          if (recvEx instanceof DriverSQLException)
3197            throw (DriverSQLException) recvEx;
3198
3199          throw new DriverSQLException(recvEx);
3200        }
3201        else if (!TypeTag.RESULTSET.equals(tag))
3202          throw new DriverSQLException(getCurrentMethodName()
3203              + ": Unexpected response for request "
3204              + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH), recvEx);
3205
3206        // Ok, we have a real non-null ResultSet, fetch it
3207
drs = new DriverResultSet(this);
3208        if (sequoiaUrl.isDebugEnabled())
3209          System.out.println("Retrieved ResultSet: " + drs);
3210      }
3211
3212      // Now fetch the OUT parameters
3213
HashMap JavaDoc outParameters = fetchOutParameters();
3214
3215      // Now fetch the named parameters
3216
HashMap JavaDoc namedParameters = fetchNamedParameters();
3217
3218      List JavaDoc result = new ArrayList JavaDoc(3);
3219      result.add(drs);
3220      result.add(outParameters);
3221      result.add(namedParameters);
3222      return new ResultAndWarnings(result, sqlw);
3223    }
3224    catch (RuntimeException JavaDoc e)
3225    {
3226      throw new DriverSQLException(getCurrentMethodName()
3227          + ": Error occured while request '"
3228          + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3229          + "' was processed by Sequoia Controller", e);
3230    }
3231    catch (IOException JavaDoc e)
3232    { // Connection failed, try to reconnect and re-exec the query
3233
try
3234      {
3235        reconnect();
3236        if (procIdIsSet)
3237        { // Controller handled the query, check if it was executed
3238
ResultAndWarnings result = retrieveExecuteQueryResultWithParameters(proc);
3239          if (result != null && result.getResultList() != null)
3240            return result;
3241        }
3242        // At this point the query failed before any controller succeeded in
3243
// executing the query
3244

3245        return callableStatementExecuteQuery(proc);
3246      }
3247      catch (DriverSQLException e1)
3248      {
3249        throw new DriverSQLException("Connection lost while executing "
3250            + getCurrentMethodName() + " on procedure request '"
3251            + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3252            + "' and automatic reconnect failed (" + e1 + ")", e1);
3253      }
3254    }
3255    catch (SerializableException se)
3256    {
3257      throw new DriverSQLException(se);
3258    }
3259  }
3260
3261  /**
3262   * Call a stored procedure that performs an update.
3263   *
3264   * @param proc the stored procedure call
3265   * @return a List composed of an Integer (number of updated rows), an
3266   * <code>ArrayList</code> of OUT parameters, and a
3267   * <code>HashMap</code> of named parameters result objects.
3268   * @exception DriverSQLException if an error occurs
3269   */

3270  protected synchronized ResultAndWarnings callableStatementExecuteUpdate(
3271      Request proc) throws DriverSQLException
3272  {
3273    throwSQLExceptionIfClosed("Closed Connection cannot process request '"
3274        + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
3275    beginTransactionIfNeeded();
3276
3277    boolean procIdIsSet = false;
3278    try
3279    {
3280      setConnectionParametersOnRequest(proc);
3281      sendCommand(Commands.CallableStatementExecuteUpdateWithParameters);
3282      proc.sendToStream(socketOutput);
3283      socketOutput.flush();
3284      if (sequoiaUrl.isDebugEnabled())
3285        System.out.println("Executing " + getCurrentMethodName()
3286            + " with procedure '" + proc + "'");
3287
3288      proc.setId(receiveLongOrException());
3289      procIdIsSet = true;
3290      if (!autoCommit)
3291        writeExecutedInTransaction = true;
3292
3293      if (sequoiaUrl.isDebugEnabled())
3294        System.out.println("Received unique id " + proc.getId()
3295            + " for procedure '" + proc + "'");
3296
3297      // Receive SQLWarnings
3298
SQLWarning JavaDoc sqlw = receiveSQLWarnings();
3299
3300      // Receive update count
3301
Integer JavaDoc updateCount = new Integer JavaDoc(receiveIntOrException());
3302
3303      // Now fetch the OUT parameters
3304
HashMap JavaDoc outParameters = fetchOutParameters();
3305
3306      // Now fetch the named parameters
3307
HashMap JavaDoc namedParameters = fetchNamedParameters();
3308
3309      List JavaDoc result = new ArrayList JavaDoc(3);
3310      result.add(updateCount);
3311      result.add(outParameters);
3312      result.add(namedParameters);
3313      return new ResultAndWarnings(result, sqlw);
3314
3315    }
3316    catch (SerializableException se)
3317    {
3318      throw new DriverSQLException(se);
3319    }
3320    catch (IOException JavaDoc e)
3321    { // Connection failed, try to reconnect and re-exec the query
3322
try
3323      {
3324        reconnect();
3325        if (procIdIsSet)
3326        { // Controller handled the query, check if it was executed
3327
ResultAndWarnings result = retrieveExecuteUpdateResultWithParameters(proc);
3328          if (result != null && result.getResultList() != null)
3329            return result;
3330        }
3331        // At this point the query failed before any controller succeeded in
3332
// executing the query
3333

3334        return callableStatementExecuteUpdate(proc);
3335      }
3336      catch (DriverSQLException e1)
3337      {
3338        throw new DriverSQLException("Connection lost while executing "
3339            + getCurrentMethodName() + " on procedure request '"
3340            + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3341            + "' and automatic reconnect failed (" + e1 + ")", e1);
3342      }
3343    }
3344  }
3345
3346  /**
3347   * Call a stored procedure that returns a list of results.
3348   *
3349   * @param proc the stored procedure call
3350   * @return a List composed of 1. <code>List</code> of results, 2.
3351   * <code>ArrayList</code> of OUT parameters, and 3.
3352   * <code>HashMap</code> of named parameters result objects.
3353   * @exception DriverSQLException if an error occurs
3354   */

3355  protected synchronized ResultAndWarnings callableStatementExecute(
3356      RequestWithResultSetParameters proc) throws DriverSQLException
3357  {
3358    throwSQLExceptionIfClosed("Closed Connection cannot process request '"
3359        + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
3360    beginTransactionIfNeeded();
3361
3362    boolean procIdIsSet = false;
3363    try
3364    {
3365      setConnectionParametersOnRequest(proc);
3366      sendCommand(Commands.CallableStatementExecuteWithParameters);
3367      proc.sendToStream(socketOutput);
3368      socketOutput.flush();
3369      if (sequoiaUrl.isDebugEnabled())
3370        System.out.println("Executing " + getCurrentMethodName()
3371            + " with procedure '" + proc + "'");
3372
3373      proc.setId(receiveLongOrException());
3374      procIdIsSet = true;
3375      if (!autoCommit)
3376        writeExecutedInTransaction = true;
3377
3378      if (sequoiaUrl.isDebugEnabled())
3379        System.out.println("Received unique id " + proc.getId()
3380            + " for procedure '" + proc + "'");
3381
3382      // Fetch warnings
3383
SQLWarning JavaDoc sqlw = receiveSQLWarnings();
3384
3385      // Fetch results
3386
List JavaDoc resultList = fetchMultipleResultsFromStream(getCurrentMethodName());
3387
3388      // Now fetch the OUT parameters
3389
HashMap JavaDoc outParameters = fetchOutParameters();
3390
3391      // Now fetch the named parameters
3392
HashMap JavaDoc namedParameters = fetchNamedParameters();
3393
3394      List JavaDoc result = new ArrayList JavaDoc(3);
3395      result.add(resultList);
3396      result.add(outParameters);
3397      result.add(namedParameters);
3398      return new ResultAndWarnings(result, sqlw);
3399    }
3400    catch (RuntimeException JavaDoc e)
3401    {
3402      throw new DriverSQLException(getCurrentMethodName()
3403          + ": Error occured while request '"
3404          + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3405          + "' was processed by Sequoia Controller", e);
3406    }
3407    catch (IOException JavaDoc e)
3408    { // Connection failed, try to reconnect and re-exec the query
3409
try
3410      {
3411        reconnect();
3412        if (procIdIsSet)
3413        { // Controller handled the query, check if it was executed
3414
ResultAndWarnings rww = retrieveExecuteResultWithParameters(proc);
3415          if (rww != null && rww.getResultList() != null)
3416            return rww;
3417        }
3418        // At this point the query failed before any controller succeeded in
3419
// executing the query
3420

3421        return callableStatementExecute(proc);
3422      }
3423      catch (DriverSQLException e1)
3424      {
3425        throw new DriverSQLException("Connection lost while executing "
3426            + getCurrentMethodName() + " with procedure request'"
3427            + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3428            + "' and automatic reconnect failed (" + e1 + ")", e1);
3429      }
3430    }
3431    catch (SerializableException e)
3432    {
3433      throw new DriverSQLException(e);
3434    }
3435  }
3436
3437  //
3438
// Database Metadata methods
3439
//
3440

3441  /**
3442   * Closes the remote ResultSet given its cursor name.
3443   *
3444   * @param cursorName cursor name of the ResultSet to close.
3445   * @throws SQLException if an error occurs
3446   */

3447  protected synchronized void closeRemoteResultSet(String JavaDoc cursorName)
3448      throws SQLException JavaDoc
3449  {
3450    throwSQLExceptionIfClosed();
3451    try
3452    {
3453      sendCommand(Commands.CloseRemoteResultSet);
3454      socketOutput.writeLongUTF(cursorName);
3455      socketOutput.flush();
3456      if (sequoiaUrl.isDebugEnabled())
3457        System.out.println("Closing remote ResultSet");
3458
3459      receiveBooleanOrException();
3460    }
3461    catch (SerializableException se)
3462    {
3463      throw new DriverSQLException(se);
3464    }
3465    catch (IOException JavaDoc e)
3466    {
3467      throw wrapIOExceptionInDriverSQLException(getCurrentMethodName(), e);
3468    }
3469  }
3470
3471  /**
3472   * @see java.sql.DatabaseMetaData#getAttributes(java.lang.String,
3473   * java.lang.String, java.lang.String, java.lang.String)
3474   */

3475  protected synchronized ResultSet JavaDoc getAttributes(String JavaDoc catalog,
3476      String JavaDoc schemaPattern, String JavaDoc typeNamePattern, String JavaDoc attributeNamePattern)
3477      throws DriverSQLException
3478  {
3479    throwSQLExceptionIfClosed();
3480    try
3481    {
3482      sendCommand(Commands.DatabaseMetaDataGetAttributes);
3483      socketOutput.writeLongUTF(catalog);
3484      socketOutput.writeLongUTF(schemaPattern);
3485      socketOutput.writeLongUTF(typeNamePattern);
3486      socketOutput.writeLongUTF(attributeNamePattern);
3487      socketOutput.flush();
3488
3489      if (sequoiaUrl.isDebugEnabled())
3490        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3491            + schemaPattern + "," + typeNamePattern + ","
3492            + attributeNamePattern + ")");
3493
3494      return receiveResultSet(getCurrentMethodName());
3495    }
3496    catch (SerializableException e)
3497    {
3498      throw new DriverSQLException(e);
3499    }
3500    catch (IOException JavaDoc e)
3501    {
3502      try
3503      {
3504        reconnect();
3505        return getAttributes(catalog, schemaPattern, typeNamePattern,
3506            attributeNamePattern);
3507      }
3508      catch (DriverSQLException e1)
3509      {
3510        throw new DriverSQLException("Connection lost while executing "
3511            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3512      }
3513    }
3514  }
3515
3516  /**
3517   * @see java.sql.DatabaseMetaData#getBestRowIdentifier(java.lang.String,
3518   * java.lang.String, java.lang.String, int, boolean)
3519   */

3520  protected synchronized ResultSet JavaDoc getBestRowIdentifier(String JavaDoc catalog,
3521      String JavaDoc schema, String JavaDoc table, int scope, boolean nullable)
3522      throws DriverSQLException
3523  {
3524    throwSQLExceptionIfClosed();
3525    try
3526    {
3527      sendCommand(Commands.DatabaseMetaDataGetBestRowIdentifier);
3528      socketOutput.writeLongUTF(catalog);
3529      socketOutput.writeLongUTF(schema);
3530      socketOutput.writeLongUTF(table);
3531      socketOutput.writeInt(scope);
3532      socketOutput.writeBoolean(nullable);
3533      socketOutput.flush();
3534
3535      if (sequoiaUrl.isDebugEnabled())
3536        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3537            + schema + "," + table + "," + scope + "," + nullable + ")");
3538
3539      return receiveResultSet(getCurrentMethodName());
3540    }
3541    catch (SerializableException e)
3542    {
3543      throw new DriverSQLException(e);
3544    }
3545    catch (IOException JavaDoc e)
3546    {
3547      try
3548      {
3549        reconnect();
3550        return getBestRowIdentifier(catalog, schema, table, scope, nullable);
3551      }
3552      catch (DriverSQLException e1)
3553      {
3554        throw new DriverSQLException("Connection lost while executing "
3555            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3556      }
3557    }
3558  }
3559
3560  /**
3561   * @see java.sql.DatabaseMetaData#getColumnPrivileges(java.lang.String,
3562   * java.lang.String, java.lang.String, java.lang.String)
3563   */

3564  protected synchronized ResultSet JavaDoc getColumnPrivileges(String JavaDoc catalog,
3565      String JavaDoc schemaPattern, String JavaDoc tableName, String JavaDoc columnNamePattern)
3566      throws DriverSQLException
3567  {
3568    throwSQLExceptionIfClosed();
3569    try
3570    {
3571      sendCommand(Commands.DatabaseMetaDataGetColumnPrivileges);
3572      socketOutput.writeLongUTF(catalog);
3573      socketOutput.writeLongUTF(schemaPattern);
3574      socketOutput.writeLongUTF(tableName);
3575      socketOutput.writeLongUTF(columnNamePattern);
3576      socketOutput.flush();
3577
3578      if (sequoiaUrl.isDebugEnabled())
3579        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3580            + schemaPattern + "," + tableName + "," + columnNamePattern + ")");
3581
3582      return receiveResultSet(getCurrentMethodName());
3583    }
3584    catch (SerializableException e)
3585    {
3586      throw new DriverSQLException(e);
3587    }
3588    catch (IOException JavaDoc e)
3589    {
3590      try
3591      {
3592        reconnect();
3593        return getColumnPrivileges(catalog, schemaPattern, tableName,
3594            columnNamePattern);
3595      }
3596      catch (DriverSQLException e1)
3597      {
3598        throw new DriverSQLException("Connection lost while executing "
3599            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3600      }
3601    }
3602  }
3603
3604  /**
3605   * @see java.sql.DatabaseMetaData#getColumns(java.lang.String,
3606   * java.lang.String, java.lang.String, java.lang.String)
3607   */

3608  protected synchronized ResultSet JavaDoc getColumns(String JavaDoc catalog,
3609      String JavaDoc schemaPattern, String JavaDoc tableNamePattern, String JavaDoc columnNamePattern)
3610      throws DriverSQLException
3611  {
3612    throwSQLExceptionIfClosed();
3613    try
3614    {
3615      sendCommand(Commands.DatabaseMetaDataGetColumns);
3616      socketOutput.writeLongUTF(catalog);
3617      socketOutput.writeLongUTF(schemaPattern);
3618      socketOutput.writeLongUTF(tableNamePattern);
3619      socketOutput.writeLongUTF(columnNamePattern);
3620      socketOutput.flush();
3621
3622      if (sequoiaUrl.isDebugEnabled())
3623        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3624            + schemaPattern + "," + tableNamePattern + "," + columnNamePattern
3625            + ")");
3626
3627      return receiveResultSet(getCurrentMethodName());
3628    }
3629    catch (SerializableException e)
3630    {
3631      throw new DriverSQLException(e);
3632    }
3633    catch (IOException JavaDoc e)
3634    {
3635      try
3636      {
3637        reconnect();
3638        return getColumns(catalog, schemaPattern, tableNamePattern,
3639            columnNamePattern);
3640      }
3641      catch (DriverSQLException e1)
3642      {
3643        throw new DriverSQLException("Connection lost while executing "
3644            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3645      }
3646    }
3647  }
3648
3649  /**
3650   * Get the Sequoia controller version number.
3651   *
3652   * @return a String containing the controller version
3653   * @exception DriverSQLException if an error occurs
3654   */

3655  protected synchronized String JavaDoc getControllerVersionNumber()
3656      throws DriverSQLException
3657  {
3658    throwSQLExceptionIfClosed();
3659    try
3660    {
3661      sendCommand(Commands.GetControllerVersionNumber);
3662      socketOutput.flush();
3663
3664      if (sequoiaUrl.isDebugEnabled())
3665        System.out.println("Executing " + getCurrentMethodName());
3666
3667      return receiveStringOrException();
3668    }
3669    catch (SerializableException e)
3670    {
3671      throw new DriverSQLException(e);
3672    }
3673    catch (IOException JavaDoc e)
3674    {
3675      try
3676      {
3677        reconnect();
3678        return getControllerVersionNumber();
3679      }
3680      catch (DriverSQLException e1)
3681      {
3682        throw new DriverSQLException("Connection lost while executing "
3683            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3684      }
3685    }
3686  }
3687
3688  /**
3689   * @see java.sql.DatabaseMetaData#getCrossReference(java.lang.String,
3690   * java.lang.String, java.lang.String, java.lang.String,
3691   * java.lang.String, java.lang.String)
3692   */

3693  protected synchronized ResultSet JavaDoc getCrossReference(String JavaDoc primaryCatalog,
3694      String JavaDoc primarySchema, String JavaDoc primaryTable, String JavaDoc foreignCatalog,
3695      String JavaDoc foreignSchema, String JavaDoc foreignTable) throws DriverSQLException
3696  {
3697    throwSQLExceptionIfClosed();
3698    try
3699    {
3700      sendCommand(Commands.DatabaseMetaDataGetCrossReference);
3701      socketOutput.writeLongUTF(primaryCatalog);
3702      socketOutput.writeLongUTF(primarySchema);
3703      socketOutput.writeLongUTF(primaryTable);
3704      socketOutput.writeLongUTF(foreignCatalog);
3705      socketOutput.writeLongUTF(foreignSchema);
3706      socketOutput.writeLongUTF(foreignTable);
3707      socketOutput.flush();
3708
3709      if (sequoiaUrl.isDebugEnabled())
3710        System.out.println(getCurrentMethodName() + "(" + primaryCatalog + ","
3711            + primarySchema + "," + primaryTable + "," + foreignCatalog + ","
3712            + foreignSchema + "," + foreignTable + ")");
3713
3714      return receiveResultSet(getCurrentMethodName());
3715    }
3716    catch (SerializableException e)
3717    {
3718      throw new DriverSQLException(e);
3719    }
3720    catch (IOException JavaDoc e)
3721    {
3722      try
3723      {
3724        reconnect();
3725        return getCrossReference(primaryCatalog, primarySchema, primaryTable,
3726            foreignCatalog, foreignSchema, foreignTable);
3727      }
3728      catch (DriverSQLException e1)
3729      {
3730        throw new DriverSQLException("Connection lost while executing "
3731            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3732      }
3733    }
3734  }
3735
3736  /**
3737   * @see DatabaseMetaData#getDatabaseProductName()
3738   */

3739  protected synchronized String JavaDoc getDatabaseProductName()
3740      throws DriverSQLException
3741  {
3742    throwSQLExceptionIfClosed();
3743    try
3744    {
3745      sendCommand(Commands.DatabaseMetaDataGetDatabaseProductName);
3746      socketOutput.flush();
3747
3748      if (sequoiaUrl.isDebugEnabled())
3749        System.out.println(getCurrentMethodName());
3750
3751      return receiveStringOrException();
3752    }
3753    catch (SerializableException e)
3754    {
3755      throw new DriverSQLException(e);
3756    }
3757    catch (IOException JavaDoc e)
3758    {
3759      try
3760      {
3761        reconnect();
3762        return getDatabaseProductName();
3763      }
3764      catch (DriverSQLException e1)
3765      {
3766        throw new DriverSQLException("Connection lost while executing "
3767            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3768      }
3769    }
3770  }
3771
3772  /**
3773   * @see java.sql.DatabaseMetaData#getExportedKeys(java.lang.String,
3774   * java.lang.String, java.lang.String)
3775   */

3776  protected synchronized ResultSet JavaDoc getExportedKeys(String JavaDoc catalog,
3777      String JavaDoc schema, String JavaDoc table) throws DriverSQLException
3778  {
3779    throwSQLExceptionIfClosed();
3780    try
3781    {
3782      sendCommand(Commands.DatabaseMetaDataGetExportedKeys);
3783      socketOutput.writeLongUTF(catalog);
3784      socketOutput.writeLongUTF(schema);
3785      socketOutput.writeLongUTF(table);
3786      socketOutput.flush();
3787
3788      if (sequoiaUrl.isDebugEnabled())
3789        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3790            + schema + "," + table + ")");
3791
3792      return receiveResultSet(getCurrentMethodName());
3793    }
3794    catch (SerializableException e)
3795    {
3796      throw new DriverSQLException(e);
3797    }
3798    catch (IOException JavaDoc e)
3799    {
3800      try
3801      {
3802        reconnect();
3803        return getExportedKeys(catalog, schema, table);
3804      }
3805      catch (DriverSQLException e1)
3806      {
3807        throw new DriverSQLException("Connection lost while executing "
3808            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3809      }
3810    }
3811  }
3812
3813  /**
3814   * @see java.sql.DatabaseMetaData#getImportedKeys(java.lang.String,
3815   * java.lang.String, java.lang.String)
3816   */

3817  protected synchronized ResultSet JavaDoc getImportedKeys(String JavaDoc catalog,
3818      String JavaDoc schema, String JavaDoc table) throws DriverSQLException
3819  {
3820    throwSQLExceptionIfClosed();
3821    try
3822    {
3823      sendCommand(Commands.DatabaseMetaDataGetImportedKeys);
3824      socketOutput.writeLongUTF(catalog);
3825      socketOutput.writeLongUTF(schema);
3826      socketOutput.writeLongUTF(table);
3827      socketOutput.flush();
3828
3829      if (sequoiaUrl.isDebugEnabled())
3830        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3831            + schema + "," + table + ")");
3832
3833      return receiveResultSet(getCurrentMethodName());
3834    }
3835    catch (SerializableException e)
3836    {
3837      throw new DriverSQLException(e);
3838    }
3839    catch (IOException JavaDoc e)
3840    {
3841      try
3842      {
3843        reconnect();
3844        return getImportedKeys(catalog, schema, table);
3845      }
3846      catch (DriverSQLException e1)
3847      {
3848        throw new DriverSQLException("Connection lost while executing "
3849            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3850      }
3851    }
3852  }
3853
3854  /**
3855   * @see java.sql.DatabaseMetaData#getIndexInfo(java.lang.String,
3856   * java.lang.String, java.lang.String, boolean, boolean)
3857   */

3858  protected synchronized ResultSet JavaDoc getIndexInfo(String JavaDoc catalog, String JavaDoc schema,
3859      String JavaDoc table, boolean unique, boolean approximate)
3860      throws DriverSQLException
3861  {
3862    throwSQLExceptionIfClosed();
3863    try
3864    {
3865      sendCommand(Commands.DatabaseMetaDataGetIndexInfo);
3866      socketOutput.writeLongUTF(catalog);
3867      socketOutput.writeLongUTF(schema);
3868      socketOutput.writeLongUTF(table);
3869      socketOutput.writeBoolean(unique);
3870      socketOutput.writeBoolean(approximate);
3871      socketOutput.flush();
3872
3873      if (sequoiaUrl.isDebugEnabled())
3874        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3875            + schema + "," + table + "," + unique + "," + approximate + ")");
3876
3877      return receiveResultSet(getCurrentMethodName());
3878    }
3879    catch (SerializableException e)
3880    {
3881      throw new DriverSQLException(e);
3882    }
3883    catch (IOException JavaDoc e)
3884    {
3885      try
3886      {
3887        reconnect();
3888        return getIndexInfo(catalog, schema, table, unique, approximate);
3889      }
3890      catch (DriverSQLException e1)
3891      {
3892        throw new DriverSQLException("Connection lost while executing "
3893            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3894      }
3895    }
3896  }
3897
3898  /**
3899   * @param sqlTemplate sql template of the PreparedStatement
3900   * @see java.sql.PreparedStatement#getMetaData()
3901   */

3902  protected synchronized ResultSetMetaData preparedStatementGetMetaData(
3903      String JavaDoc sqlTemplate) throws DriverSQLException
3904  {
3905    throwSQLExceptionIfClosed();
3906    try
3907    {
3908      sendCommand(Commands.PreparedStatementGetMetaData);
3909      socketOutput.writeLongUTF(sqlTemplate);
3910      socketOutput.flush();
3911
3912      if (sequoiaUrl.isDebugEnabled())
3913        System.out.println(getCurrentMethodName() + "()");
3914
3915      return receiveResultSet(getCurrentMethodName()).getMetaData();
3916    }
3917    catch (SerializableException e)
3918    {
3919      throw new DriverSQLException(e);
3920    }
3921    catch (SQLException JavaDoc e)
3922    {
3923      throw new DriverSQLException(e);
3924    }
3925    catch (IOException JavaDoc e)
3926    {
3927      try
3928      {
3929        reconnect();
3930        return preparedStatementGetMetaData(sqlTemplate);
3931      }
3932      catch (DriverSQLException e1)
3933      {
3934        throw new DriverSQLException("Connection lost while executing "
3935            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3936      }
3937    }
3938  }
3939
3940  /**
3941   * @see java.sql.DatabaseMetaData#getPrimaryKeys(java.lang.String,
3942   * java.lang.String, java.lang.String)
3943   */

3944  protected synchronized ResultSet JavaDoc getPrimaryKeys(String JavaDoc catalog,
3945      String JavaDoc schemaPattern, String JavaDoc tableNamePattern) throws DriverSQLException
3946  {
3947    throwSQLExceptionIfClosed();
3948    try
3949    {
3950      sendCommand(Commands.DatabaseMetaDataGetPrimaryKeys);
3951      socketOutput.writeLongUTF(catalog);
3952      socketOutput.writeLongUTF(schemaPattern);
3953      socketOutput.writeLongUTF(tableNamePattern);
3954      socketOutput.flush();
3955
3956      if (sequoiaUrl.isDebugEnabled())
3957        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3958            + schemaPattern + "," + tableNamePattern + ")");
3959
3960      return receiveResultSet(getCurrentMethodName());
3961    }
3962    catch (SerializableException e)
3963    {
3964      throw new DriverSQLException(e);
3965    }
3966    catch (IOException JavaDoc e)
3967    {
3968      try
3969      {
3970        reconnect();
3971        return getPrimaryKeys(catalog, schemaPattern, tableNamePattern);
3972      }
3973      catch (DriverSQLException e1)
3974      {
3975        throw new DriverSQLException("Connection lost while executing "
3976            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
3977      }
3978    }
3979  }
3980
3981  protected synchronized java.sql.ResultSet JavaDoc getProcedures(String JavaDoc catalog,
3982      String JavaDoc schemaPattern, String JavaDoc procedureNamePattern)
3983      throws DriverSQLException
3984  {
3985    throwSQLExceptionIfClosed();
3986    try
3987    {
3988      sendCommand(Commands.DatabaseMetaDataGetProcedures);
3989      socketOutput.writeLongUTF(catalog);
3990      socketOutput.writeLongUTF(schemaPattern);
3991      socketOutput.writeLongUTF(procedureNamePattern);
3992      socketOutput.flush();
3993
3994      if (sequoiaUrl.isDebugEnabled())
3995        System.out.println(getCurrentMethodName() + "(" + catalog + ","
3996            + schemaPattern + "," + procedureNamePattern + ")");
3997
3998      return receiveResultSet(getCurrentMethodName());
3999    }
4000    catch (SerializableException e)
4001    {
4002      throw new DriverSQLException(e);
4003    }
4004    catch (IOException JavaDoc e)
4005    {
4006      try
4007      {
4008        reconnect();
4009        return getProcedures(catalog, schemaPattern, procedureNamePattern);
4010      }
4011      catch (DriverSQLException e1)
4012      {
4013        throw new DriverSQLException("Connection lost while executing "
4014            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4015      }
4016    }
4017  }
4018
4019  protected synchronized java.sql.ResultSet JavaDoc getProcedureColumns(String JavaDoc catalog,
4020      String JavaDoc schemaPattern, String JavaDoc procedureNamePattern,
4021      String JavaDoc columnNamePattern) throws DriverSQLException
4022  {
4023    throwSQLExceptionIfClosed();
4024    try
4025    {
4026      sendCommand(Commands.DatabaseMetaDataGetProcedureColumns);
4027      socketOutput.writeLongUTF(catalog);
4028      socketOutput.writeLongUTF(schemaPattern);
4029      socketOutput.writeLongUTF(procedureNamePattern);
4030      socketOutput.writeLongUTF(columnNamePattern);
4031      socketOutput.flush();
4032
4033      if (sequoiaUrl.isDebugEnabled())
4034        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4035            + schemaPattern + "," + procedureNamePattern + ","
4036            + columnNamePattern + ")");
4037
4038      return receiveResultSet(getCurrentMethodName());
4039    }
4040    catch (SerializableException e)
4041    {
4042      throw new DriverSQLException(e);
4043    }
4044    catch (IOException JavaDoc e)
4045    {
4046      try
4047      {
4048        reconnect();
4049        return getProcedureColumns(catalog, schemaPattern,
4050            procedureNamePattern, columnNamePattern);
4051      }
4052      catch (DriverSQLException e1)
4053      {
4054        throw new DriverSQLException("Connection lost while executing "
4055            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4056      }
4057    }
4058  }
4059
4060  /**
4061   * @see java.sql.DatabaseMetaData#getSchemas()
4062   */

4063  protected synchronized ResultSet JavaDoc getSchemas() throws DriverSQLException
4064  {
4065    throwSQLExceptionIfClosed();
4066
4067    try
4068    {
4069      sendCommand(Commands.DatabaseMetaDataGetSchemas);
4070      socketOutput.flush();
4071
4072      if (sequoiaUrl.isDebugEnabled())
4073        System.out.println(getCurrentMethodName());
4074
4075      return receiveResultSet(getCurrentMethodName());
4076    }
4077    catch (SerializableException e)
4078    {
4079      throw new DriverSQLException(e);
4080    }
4081    catch (IOException JavaDoc e)
4082    {
4083      try
4084      {
4085        reconnect();
4086        return getSchemas();
4087      }
4088      catch (DriverSQLException e1)
4089      {
4090        throw new DriverSQLException("Connection lost while executing "
4091            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4092      }
4093    }
4094  }
4095
4096  /**
4097   * @see java.sql.DatabaseMetaData#getSuperTables(java.lang.String,
4098   * java.lang.String, java.lang.String)
4099   */

4100  protected synchronized ResultSet JavaDoc getSuperTables(String JavaDoc catalog,
4101      String JavaDoc schemaPattern, String JavaDoc tableNamePattern) throws DriverSQLException
4102  {
4103    throwSQLExceptionIfClosed();
4104    try
4105    {
4106      sendCommand(Commands.DatabaseMetaDataGetSuperTables);
4107      socketOutput.writeLongUTF(catalog);
4108      socketOutput.writeLongUTF(schemaPattern);
4109      socketOutput.writeLongUTF(tableNamePattern);
4110      socketOutput.flush();
4111
4112      if (sequoiaUrl.isDebugEnabled())
4113        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4114            + schemaPattern + "," + tableNamePattern + ")");
4115
4116      return receiveResultSet(getCurrentMethodName());
4117    }
4118    catch (SerializableException e)
4119    {
4120      throw new DriverSQLException(e);
4121    }
4122    catch (IOException JavaDoc e)
4123    {
4124      try
4125      {
4126        reconnect();
4127        return getSuperTables(catalog, schemaPattern, tableNamePattern);
4128      }
4129      catch (DriverSQLException e1)
4130      {
4131        throw new DriverSQLException("Connection lost while executing "
4132            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4133      }
4134    }
4135  }
4136
4137  /**
4138   * @see java.sql.DatabaseMetaData#getSuperTypes(java.lang.String,
4139   * java.lang.String, java.lang.String)
4140   */

4141  protected synchronized ResultSet JavaDoc getSuperTypes(String JavaDoc catalog,
4142      String JavaDoc schemaPattern, String JavaDoc typeNamePattern) throws DriverSQLException
4143  {
4144    throwSQLExceptionIfClosed();
4145    try
4146    {
4147      sendCommand(Commands.DatabaseMetaDataGetSuperTypes);
4148      socketOutput.writeLongUTF(catalog);
4149      socketOutput.writeLongUTF(schemaPattern);
4150      socketOutput.writeLongUTF(typeNamePattern);
4151      socketOutput.flush();
4152
4153      if (sequoiaUrl.isDebugEnabled())
4154        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4155            + schemaPattern + "," + typeNamePattern + ")");
4156
4157      return receiveResultSet(getCurrentMethodName());
4158    }
4159    catch (SerializableException e)
4160    {
4161      throw new DriverSQLException(e);
4162    }
4163    catch (IOException JavaDoc e)
4164    {
4165      try
4166      {
4167        reconnect();
4168        return getSuperTypes(catalog, schemaPattern, typeNamePattern);
4169      }
4170      catch (DriverSQLException e1)
4171      {
4172        throw new DriverSQLException(
4173            "Connection lost while executing getSuperTypes and automatic reconnect failed ",
4174            e1);
4175      }
4176    }
4177  }
4178
4179  /**
4180   * Retrieve a static metadata from the controller.
4181   *
4182   * @param key the "getXXX(Y,Z,...)" hash key of the metadata query
4183   * @return an Object that will be an <tt>Integer</tt> or <tt>Boolean</tt>
4184   * or <tt>String</tt>
4185   * @throws DriverSQLException if fails
4186   * @see org.continuent.sequoia.controller.virtualdatabase.VirtualDatabaseWorkerThread#databaseStaticMetadata()
4187   * @see org.continuent.sequoia.controller.backend.DatabaseBackendMetaData#retrieveDatabaseMetadata()
4188   */

4189  protected synchronized Object JavaDoc getStaticMetadata(String JavaDoc key)
4190      throws DriverSQLException
4191  {
4192    throwSQLExceptionIfClosed();
4193    try
4194    {
4195      sendCommand(Commands.DatabaseStaticMetadata);
4196      socketOutput.writeLongUTF(key);
4197      socketOutput.flush();
4198      if (sequoiaUrl.isDebugEnabled())
4199        System.out.println("Getting " + key + " metadata");
4200
4201      TypeTag tag = new TypeTag(socketInput);
4202
4203      if (TypeTag.EXCEPTION.equals(tag))
4204        throw new DriverSQLException(receiveException());
4205      else
4206      {
4207        tag = new TypeTag(socketInput);
4208        Object JavaDoc result = SQLDataSerialization.getSerializer(tag)
4209            .receiveFromStream(socketInput);
4210        return result;
4211      }
4212    }
4213    catch (IOException JavaDoc e)
4214    {
4215      try
4216      {
4217        reconnect();
4218        return getStaticMetadata(key);
4219      }
4220      catch (DriverSQLException e1)
4221      {
4222        throw new DriverSQLException("Connection lost while executing "
4223            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4224      }
4225    }
4226  }
4227
4228  /**
4229   * Gets a description of the access rights for each table available in a
4230   * catalog. Note that a table privilege applies to one or more columns in the
4231   * table. It would be wrong to assume that this priviledge applies to all
4232   * columns (this may be true for some systems but is not true for all.) Only
4233   * privileges matching the schema and table name criteria are returned. They
4234   * are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
4235   *
4236   * @param catalog a catalog name; "" retrieves those without a catalog; null
4237   * means drop catalog name from the selection criteria
4238   * @param schemaPattern a schema name pattern; "" retrieves those without a
4239   * schema
4240   * @param tableNamePattern a table name pattern
4241   * @return <code>ResultSet</code> each row is a table privilege description
4242   * @throws DriverSQLException if a database access error occurs
4243   */

4244  protected synchronized ResultSet JavaDoc getTablePrivileges(String JavaDoc catalog,
4245      String JavaDoc schemaPattern, String JavaDoc tableNamePattern) throws DriverSQLException
4246  {
4247    throwSQLExceptionIfClosed();
4248    try
4249    {
4250      sendCommand(Commands.DatabaseMetaDataGetTablePrivileges);
4251      socketOutput.writeLongUTF(catalog);
4252      socketOutput.writeLongUTF(schemaPattern);
4253      socketOutput.writeLongUTF(tableNamePattern);
4254      socketOutput.flush();
4255
4256      if (sequoiaUrl.isDebugEnabled())
4257        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4258            + schemaPattern + "," + tableNamePattern + ")");
4259
4260      return receiveResultSet(getCurrentMethodName());
4261    }
4262    catch (SerializableException e)
4263    {
4264      throw new DriverSQLException(e);
4265    }
4266    catch (IOException JavaDoc e)
4267    {
4268      try
4269      {
4270        reconnect();
4271        return getTablePrivileges(catalog, schemaPattern, tableNamePattern);
4272      }
4273      catch (DriverSQLException e1)
4274      {
4275        throw new DriverSQLException("Connection lost while executing "
4276            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4277      }
4278    }
4279  }
4280
4281  /**
4282   * @see org.continuent.sequoia.driver.DatabaseMetaData#getTables(String,
4283   * String, String, String[])
4284   */

4285  protected synchronized ResultSet JavaDoc getTables(String JavaDoc catalog,
4286      String JavaDoc schemaPattern, String JavaDoc tableNamePattern, String JavaDoc[] types)
4287      throws DriverSQLException
4288  {
4289    throwSQLExceptionIfClosed();
4290    try
4291    {
4292      sendCommand(Commands.DatabaseMetaDataGetTables);
4293      socketOutput.writeLongUTF(catalog);
4294      socketOutput.writeLongUTF(schemaPattern);
4295      socketOutput.writeLongUTF(tableNamePattern);
4296
4297      if (null == types)
4298        socketOutput.writeBoolean(false);
4299      else
4300      {
4301        socketOutput.writeBoolean(true);
4302        socketOutput.writeInt(types.length);
4303        for (int i = 0; i < types.length; i++)
4304          socketOutput.writeLongUTF(types[i]);
4305      }
4306      socketOutput.flush();
4307
4308      if (sequoiaUrl.isDebugEnabled())
4309        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4310            + schemaPattern + "," + tableNamePattern + "," + types + ")");
4311
4312      return receiveResultSet(getCurrentMethodName());
4313    }
4314    catch (SerializableException e)
4315    {
4316      throw new DriverSQLException(e);
4317    }
4318    catch (IOException JavaDoc e)
4319    {
4320      try
4321      {
4322        reconnect();
4323        return getTables(catalog, schemaPattern, tableNamePattern, types);
4324      }
4325      catch (DriverSQLException e1)
4326      {
4327        throw new DriverSQLException("Connection lost while executing "
4328            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4329      }
4330    }
4331  }
4332
4333  /**
4334   * Gets the table types available in this database. The results are ordered by
4335   * table type.
4336   *
4337   * @return <code>ResultSet</code> each row has a single String column that
4338   * is a catalog name
4339   * @throws SQLException if a database error occurs
4340   */

4341  protected synchronized ResultSet JavaDoc getTableTypes() throws SQLException JavaDoc
4342  {
4343    throwSQLExceptionIfClosed();
4344    try
4345    {
4346      sendCommand(Commands.DatabaseMetaDataGetTableTypes);
4347      socketOutput.flush();
4348
4349      if (sequoiaUrl.isDebugEnabled())
4350        System.out.println(getCurrentMethodName());
4351
4352      return receiveResultSet(getCurrentMethodName());
4353    }
4354    catch (SerializableException e)
4355    {
4356      throw new DriverSQLException(e);
4357    }
4358    catch (IOException JavaDoc e)
4359    {
4360      try
4361      {
4362        reconnect();
4363        return getTableTypes();
4364      }
4365      catch (DriverSQLException e1)
4366      {
4367        throw new DriverSQLException("Connection lost while executing "
4368            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4369      }
4370    }
4371  }
4372
4373  /**
4374   * @see java.sql.DatabaseMetaData#getTypeInfo()
4375   */

4376  protected synchronized ResultSet JavaDoc getTypeInfo() throws DriverSQLException
4377  {
4378    throwSQLExceptionIfClosed();
4379    try
4380    {
4381      sendCommand(Commands.DatabaseMetaDataGetTypeInfo);
4382      socketOutput.flush();
4383
4384      if (sequoiaUrl.isDebugEnabled())
4385        System.out.println(getCurrentMethodName() + "()");
4386
4387      return receiveResultSet(getCurrentMethodName());
4388    }
4389    catch (SerializableException e)
4390    {
4391      throw new DriverSQLException(e);
4392    }
4393    catch (IOException JavaDoc e)
4394    {
4395      try
4396      {
4397        reconnect();
4398        return getTypeInfo();
4399      }
4400      catch (DriverSQLException e1)
4401      {
4402        throw new DriverSQLException("Connection lost while executing "
4403            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4404      }
4405    }
4406  }
4407
4408  /**
4409   * @see java.sql.DatabaseMetaData#getUDTs(java.lang.String, java.lang.String,
4410   * java.lang.String, int[])
4411   */

4412  protected synchronized ResultSet JavaDoc getUDTs(String JavaDoc catalog,
4413      String JavaDoc schemaPattern, String JavaDoc typeNamePattern, int[] types)
4414      throws DriverSQLException
4415  {
4416    throwSQLExceptionIfClosed();
4417    try
4418    {
4419      sendCommand(Commands.DatabaseMetaDataGetUDTs);
4420      socketOutput.writeLongUTF(catalog);
4421      socketOutput.writeLongUTF(schemaPattern);
4422      socketOutput.writeLongUTF(typeNamePattern);
4423
4424      if (null == types)
4425        socketOutput.writeBoolean(false);
4426      else
4427      {
4428        socketOutput.writeBoolean(true);
4429        socketOutput.writeInt(types.length);
4430        for (int i = 0; i < types.length; i++)
4431          socketOutput.writeInt(types[i]);
4432      }
4433      socketOutput.flush();
4434
4435      if (sequoiaUrl.isDebugEnabled())
4436        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4437            + schemaPattern + "," + typeNamePattern + "," + types + ")");
4438
4439      return receiveResultSet(getCurrentMethodName());
4440    }
4441    catch (SerializableException e)
4442    {
4443      throw new DriverSQLException(e);
4444    }
4445    catch (IOException JavaDoc e)
4446    {
4447      try
4448      {
4449        reconnect();
4450        return getUDTs(catalog, schemaPattern, typeNamePattern, types);
4451      }
4452      catch (DriverSQLException e1)
4453      {
4454        throw new DriverSQLException("Connection lost while executing "
4455            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4456      }
4457    }
4458  }
4459
4460  /**
4461   * @see java.sql.DatabaseMetaData#getVersionColumns(java.lang.String,
4462   * java.lang.String, java.lang.String)
4463   */

4464  protected synchronized ResultSet JavaDoc getVersionColumns(String JavaDoc catalog,
4465      String JavaDoc schema, String JavaDoc table) throws DriverSQLException
4466  {
4467    throwSQLExceptionIfClosed();
4468    try
4469    {
4470      sendCommand(Commands.DatabaseMetaDataGetVersionColumns);
4471      socketOutput.writeLongUTF(catalog);
4472      socketOutput.writeLongUTF(schema);
4473      socketOutput.writeLongUTF(table);
4474      socketOutput.flush();
4475
4476      if (sequoiaUrl.isDebugEnabled())
4477        System.out.println(getCurrentMethodName() + "(" + catalog + ","
4478            + schema + "," + table + ")");
4479
4480      return receiveResultSet(getCurrentMethodName());
4481    }
4482    catch (SerializableException e)
4483    {
4484      throw new DriverSQLException(e);
4485    }
4486    catch (IOException JavaDoc e)
4487    {
4488      try
4489      {
4490        reconnect();
4491        return getVersionColumns(catalog, schema, table);
4492      }
4493      catch (DriverSQLException e1)
4494      {
4495        throw new DriverSQLException("Connection lost while executing "
4496            + getCurrentMethodName() + " and automatic reconnect failed ", e1);
4497      }
4498    }
4499  }
4500
4501  /**
4502   * Send "FetchNextResultSetRows" command to controller. Throws an SQL
4503   * exception if controller returns an error; else returns void and lets the
4504   * caller receive its new rows by itself.
4505   *
4506   * @see org.continuent.sequoia.controller.virtualdatabase.VirtualDatabaseWorkerThread#fetchNextResultSetRows()
4507   * @param cursorName name of the ResultSet cursor
4508   * @param fetchSize number of rows to fetch
4509   * @throws DriverSQLException if an error occurs
4510   */

4511  protected synchronized void tryFetchNext(String JavaDoc cursorName, int fetchSize)
4512      throws DriverSQLException
4513  {
4514    throwSQLExceptionIfClosed();
4515    try
4516    {
4517      sendCommand(Commands.FetchNextResultSetRows);
4518      socketOutput.writeLongUTF(cursorName);
4519      socketOutput.writeInt(fetchSize);
4520      socketOutput.flush();
4521      if (sequoiaUrl.isDebugEnabled())
4522        System.out
4523            .println("Fetching next " + fetchSize + " from " + cursorName);
4524
4525      TypeTag tag = new TypeTag(socketInput);
4526
4527      if (TypeTag.EXCEPTION.equals(tag))
4528        throw new DriverSQLException(receiveException());
4529
4530      if (!TypeTag.NOT_EXCEPTION.equals(tag))
4531        throw new ProtocolException();
4532
4533      // success, now we can let the DriverResultSet caller receive its data.
4534

4535    }
4536    catch (IOException JavaDoc e)
4537    {
4538      throw wrapIOExceptionInDriverSQLException(getCurrentMethodName(), e);
4539    }
4540  }
4541
4542  /**
4543   * Gets the caller's method name.
4544   *
4545   * @return method name of the calling function
4546   */

4547  static String JavaDoc getCurrentMethodName()
4548  {
4549    return new Throwable JavaDoc().getStackTrace()[1].getMethodName();
4550  }
4551
4552  /**
4553   * @see java.lang.Object#toString()
4554   */

4555  public String JavaDoc toString()
4556  {
4557    // we could use println() instead of LINE_SEPARATOR here
4558
return "url:"
4559        + getUrl()
4560        + LINE_SEPARATOR
4561        + socket
4562        + LINE_SEPARATOR
4563        + ((sequoiaUrl != null) && (sequoiaUrl.getParameters() != null)
4564            ? "properties:" + sequoiaUrl.getParameters() + LINE_SEPARATOR
4565            : "") + "user:" + getUserName() + LINE_SEPARATOR
4566        + "connection pooling:" + connectionPooling + LINE_SEPARATOR
4567        + "escape backslash:" + escapeBackslash + LINE_SEPARATOR
4568        + "escape char:" + escapeChar + LINE_SEPARATOR + "escape single quote:"
4569        + escapeSingleQuote + LINE_SEPARATOR;
4570  }
4571}
4572
Free Books   Free Magazines  
Popular Tags