Source Code Cross Referenced for Connection.java in  » Database-JDBC-Connection-Pool » sequoia-2.10.9 » org » continuent » sequoia » driver » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » sequoia 2.10.9 » org.continuent.sequoia.driver 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * Sequoia: Database clustering technology.
0003:         * Copyright (C) 2002-2004 French National Institute For Research In Computer
0004:         * Science And Control (INRIA).
0005:         * Copyright (C) 2005-2006 Continuent, Inc.
0006:         * Contact: sequoia@continuent.org
0007:         * 
0008:         * Licensed under the Apache License, Version 2.0 (the "License");
0009:         * you may not use this file except in compliance with the License.
0010:         * You may obtain a copy of the License at
0011:         * 
0012:         * http://www.apache.org/licenses/LICENSE-2.0
0013:         * 
0014:         * Unless required by applicable law or agreed to in writing, software
0015:         * distributed under the License is distributed on an "AS IS" BASIS,
0016:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:         * See the License for the specific language governing permissions and
0018:         * limitations under the License. 
0019:         *
0020:         * Initial developer(s): Emmanuel Cecchet. 
0021:         * Contributor(s): Julie Marguerite, Guillaume Bort, Duncan Smith, Vadim Kassin,
0022:         * Nicolas Modrzyk, Jaco Swart,  Jean-Bernard van Zuylen
0023:         * Completely refactored by Marc Herbert to remove the use of Java serialization.
0024:         */package org.continuent.sequoia.driver;
0025:
0026:        import java.io.IOException;
0027:        import java.net.Socket;
0028:        import java.security.GeneralSecurityException;
0029:        import java.sql.ResultSet;
0030:        import java.sql.ResultSetMetaData;
0031:        import java.sql.SQLException;
0032:        import java.sql.SQLWarning;
0033:        import java.sql.Savepoint;
0034:        import java.util.ArrayList;
0035:        import java.util.HashMap;
0036:        import java.util.Iterator;
0037:        import java.util.LinkedList;
0038:        import java.util.List;
0039:        import java.util.Map;
0040:
0041:        import org.continuent.sequoia.common.exceptions.AuthenticationException;
0042:        import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
0043:        import org.continuent.sequoia.common.exceptions.NoMoreControllerException;
0044:        import org.continuent.sequoia.common.exceptions.NotImplementedException;
0045:        import org.continuent.sequoia.common.exceptions.ProtocolException;
0046:        import org.continuent.sequoia.common.exceptions.driver.DriverIOException;
0047:        import org.continuent.sequoia.common.exceptions.driver.DriverSQLException;
0048:        import org.continuent.sequoia.common.exceptions.driver.VirtualDatabaseUnavailableException;
0049:        import org.continuent.sequoia.common.exceptions.driver.protocol.BackendDriverException;
0050:        import org.continuent.sequoia.common.exceptions.driver.protocol.ControllerCoreException;
0051:        import org.continuent.sequoia.common.exceptions.driver.protocol.SerializableException;
0052:        import org.continuent.sequoia.common.protocol.Commands;
0053:        import org.continuent.sequoia.common.protocol.SQLDataSerialization;
0054:        import org.continuent.sequoia.common.protocol.TypeTag;
0055:        import org.continuent.sequoia.common.protocol.SQLDataSerialization.Serializer;
0056:        import org.continuent.sequoia.common.sql.Request;
0057:        import org.continuent.sequoia.common.sql.RequestWithResultSetParameters;
0058:        import org.continuent.sequoia.common.stream.DriverBufferedInputStream;
0059:        import org.continuent.sequoia.common.stream.DriverBufferedOutputStream;
0060:
0061:        /**
0062:         * This class implements the communication protocol to the Controller.
0063:         * <p>
0064:         * Connection.java was inspired from the PostgreSQL JDBC driver by Peter T.
0065:         * Mount.
0066:         * 
0067:         * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
0068:         * @author <a href="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
0069:         * @author <a href="mailto:vadim@kase.kz">Vadim Kassin </a>
0070:         * @author <a href="mailto:duncan@mightybot.com">Duncan Smith </a>
0071:         * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
0072:         * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
0073:         * @author <a href="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
0074:         * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
0075:         *         </a>
0076:         * @version 2.0
0077:         */
0078:        public class Connection implements  java.sql.Connection {
0079:            /** Status of the connection. */
0080:            protected boolean isClosed = false;
0081:
0082:            protected String escapeChar;
0083:
0084:            /** Sequoia controller we are connected to */
0085:            protected ControllerInfo controllerInfo = null;
0086:
0087:            // ConnectionClosingThread
0088:            /** Driver that created us. */
0089:            protected Driver driver = null;
0090:
0091:            /** Connection with the controller. */
0092:            protected Socket socket;
0093:            /** Socket input stream. */
0094:            protected DriverBufferedInputStream socketInput;
0095:            /** Socket output stream. */
0096:            protected DriverBufferedOutputStream socketOutput;
0097:
0098:            /** @see org.continuent.sequoia.controller.core.ControllerConstants#SQL_SHORT_FORM_LENGTH */
0099:            public static final int ABBREV_REQUEST_LENGTH = 40;
0100:
0101:            // used by Statement (and maybe also by some others _below_)
0102:            static final String LINE_SEPARATOR = System
0103:                    .getProperty("line.separator");
0104:
0105:            // Member variables describing the state of the connection
0106:
0107:            /** Commit mode of the connection (<code>true</code>= automatic). */
0108:            protected boolean autoCommit = true;
0109:
0110:            /** Is the connection in read-only mode ? */
0111:            protected boolean readOnly = false;
0112:
0113:            /** Has a write request been executed in the current transaction? */
0114:            boolean writeExecutedInTransaction = false;
0115:
0116:            /** Default transaction isolation level if the user has not enforced one */
0117:            public static final int DEFAULT_TRANSACTION_ISOLATION_LEVEL = -1;
0118:
0119:            /** Current transaction isolation level. */
0120:            protected int isolationLevel = DEFAULT_TRANSACTION_ISOLATION_LEVEL;
0121:
0122:            /** transaction identifier. */
0123:            protected long transactionId = 0;
0124:
0125:            /** List of <code>Warnings</code> for this connection. */
0126:            protected SQLWarning firstWarning = null;
0127:
0128:            /** ResultSet holdability (JDBC 3) */
0129:            protected int holdability = HOLDABILITY_NOT_SET;
0130:            private static final int HOLDABILITY_NOT_SET = -1;
0131:
0132:            /** Meta-data of Sequoia connections. */
0133:            protected DatabaseMetaData metaData = null;
0134:
0135:            /** Parsed URL to the database. */
0136:            private final SequoiaUrl sequoiaUrl;
0137:
0138:            /** Virtual database user used for this connection. */
0139:            protected String vdbUser = null;
0140:            protected String vdbPassword = null;
0141:
0142:            private boolean connectionPooling;
0143:
0144:            // Escape processing tuning
0145:            protected boolean escapeBackslash;
0146:            protected boolean escapeSingleQuote;
0147:
0148:            // flag to check if a new transaction must be
0149:            // started before executing any statement
0150:            private boolean mustBeginTransaction = false;
0151:
0152:            // True if the connection must be persisted on all cluster backends even when
0153:            // autoCommit=true
0154:            private boolean persistentConnection;
0155:
0156:            // Persistent connection identifier if persistentConnection is true
0157:            private long persistentConnectionId;
0158:
0159:            // Do we want SQL Warnings ?
0160:            private boolean retrieveSQLWarnings = false;
0161:
0162:            // Do we force generated keys to be retrieved?
0163:            private boolean alwaysGetGeneratedKeys = false;
0164:
0165:            /*****************************************************************************
0166:             * *************** * Constructor and get/set methods * ***********************
0167:             * ****************************************************************************
0168:             */
0169:
0170:            /**
0171:             * Creates a new <code>Connection</code> instance.
0172:             * 
0173:             * @param driver calling driver
0174:             * @param socket connection with the controller
0175:             * @param in socket input stream
0176:             * @param out socket output stream
0177:             * @param sequoiaUrl Sequoia URL of the database
0178:             * @param controller controller we are connected to
0179:             * @param userName user login
0180:             * @param password user password
0181:             * @throws AuthenticationException login error
0182:             * @throws IOException stream error
0183:             * @throws SQLException if the virtual database is not available on the
0184:             *           controller
0185:             */
0186:            Connection(Driver driver, Socket socket,
0187:                    DriverBufferedInputStream in,
0188:                    DriverBufferedOutputStream out, SequoiaUrl sequoiaUrl,
0189:                    ControllerInfo controller, String userName, String password)
0190:                    throws AuthenticationException, IOException,
0191:                    VirtualDatabaseUnavailableException {
0192:                this .driver = driver;
0193:                this .socket = socket;
0194:                this .socketInput = in;
0195:                this .socketOutput = out;
0196:                this .sequoiaUrl = sequoiaUrl;
0197:                this .controllerInfo = controller;
0198:                this .vdbUser = userName;
0199:                this .vdbPassword = password;
0200:
0201:                escapeBackslash = driver.getEscapeBackslash();
0202:                escapeChar = driver.getEscapeChar();
0203:                escapeSingleQuote = driver.getEscapeSingleQuote();
0204:                connectionPooling = driver.getConnectionPooling();
0205:                persistentConnection = driver.getPersistentConnection();
0206:                retrieveSQLWarnings = driver.getRetrieveSQLWarnings();
0207:                alwaysGetGeneratedKeys = driver.getRetrieveGeneratedKeys();
0208:
0209:                // Is virtual database available?
0210:                if (!in.readBoolean()) // failed
0211:                    throw new VirtualDatabaseUnavailableException(in
0212:                            .readLongUTF());
0213:
0214:                // Is authentication successful?
0215:                if (!in.readBoolean()) // failed
0216:                    throw new AuthenticationException(in.readLongUTF());
0217:
0218:                setUrlParametersOptionsOnConnection(sequoiaUrl);
0219:
0220:                out.writeLongUTF(LINE_SEPARATOR);
0221:                out.writeBoolean(persistentConnection);
0222:                out.flush();
0223:
0224:                if (persistentConnection) {
0225:                    if (in.readBoolean())
0226:                        persistentConnectionId = in.readLong();
0227:                    else
0228:                        throw new AuthenticationException(
0229:                                "No more persistent connections available for virtual database "
0230:                                        + sequoiaUrl.getDatabaseName()
0231:                                        + "[url=" + sequoiaUrl + "]");
0232:                }
0233:
0234:                out.writeBoolean(retrieveSQLWarnings);
0235:                out.flush();
0236:
0237:                if (sequoiaUrl.isDebugEnabled())
0238:                    System.out.println("New connection:" + this .toString());
0239:            }
0240:
0241:            /**
0242:             * Set SequoiaUrl parameters options on connection.
0243:             * 
0244:             * @param sequoiaUrl the Sequoia URL to use
0245:             */
0246:            private void setUrlParametersOptionsOnConnection(
0247:                    SequoiaUrl sequoiaUrl) {
0248:                HashMap sequoiaUrlParameters = sequoiaUrl.getParameters();
0249:
0250:                String escapeBaskslash = (String) sequoiaUrlParameters
0251:                        .get(Driver.ESCAPE_BACKSLASH_PROPERTY);
0252:                if (escapeBaskslash != null)
0253:                    setEscapeBackslash(new Boolean(escapeBaskslash)
0254:                            .booleanValue());
0255:
0256:                String escapeQuote = (String) sequoiaUrlParameters
0257:                        .get(Driver.ESCAPE_SINGLE_QUOTE_PROPERTY);
0258:                if (escapeQuote != null)
0259:                    setEscapeSingleQuote(new Boolean(escapeQuote)
0260:                            .booleanValue());
0261:
0262:                String escapeCharacter = (String) sequoiaUrlParameters
0263:                        .get(Driver.ESCAPE_CHARACTER_PROPERTY);
0264:                if (escapeCharacter != null)
0265:                    setEscapeChar(escapeCharacter);
0266:
0267:                // true if transparent connection pooling must be used
0268:                String connPool = (String) sequoiaUrlParameters
0269:                        .get(Driver.CONNECTION_POOLING_PROPERTY);
0270:                if (connPool != null)
0271:                    this .connectionPooling = "true".equals(connPool);
0272:
0273:                String persistentConn = (String) sequoiaUrlParameters
0274:                        .get(Driver.PERSISTENT_CONNECTION_PROPERTY);
0275:                if (persistentConn != null)
0276:                    this .persistentConnection = "true".equals(persistentConn);
0277:
0278:                String retSQLWarns = (String) sequoiaUrlParameters
0279:                        .get(Driver.RETRIEVE_SQL_WARNINGS_PROPERTY);
0280:                if (retSQLWarns != null)
0281:                    this .retrieveSQLWarnings = "true".equals(retSQLWarns);
0282:
0283:                String retGeneratedKeys = (String) sequoiaUrlParameters
0284:                        .get(Driver.ALWAYS_RETRIEVE_GENERATED_KEYS_PROPERTY);
0285:                if (retGeneratedKeys != null)
0286:                    this .alwaysGetGeneratedKeys = "true"
0287:                            .equals(retGeneratedKeys);
0288:
0289:                if (sequoiaUrl.isDebugEnabled()) {
0290:                    // Give a warning for unrecognized driver options in the URL
0291:                    // (only in the URL: unknown properties have been filtered out)
0292:                    for (Iterator iter = sequoiaUrlParameters.entrySet()
0293:                            .iterator(); iter.hasNext();) {
0294:                        Map.Entry e = (Map.Entry) iter.next();
0295:                        String param = (String) e.getKey();
0296:                        if (!Driver.driverPropertiesNames.contains(param))
0297:                            System.out
0298:                                    .println("Unrecognized driver parameter: "
0299:                                            + param + " = "
0300:                                            + (String) e.getValue());
0301:                    }
0302:                }
0303:            }
0304:
0305:            /**
0306:             * Get the information about the controller we are connected to
0307:             * 
0308:             * @return <code>ControllerInfo</code> object of the controller
0309:             */
0310:            public ControllerInfo getControllerInfo() {
0311:                return controllerInfo;
0312:            }
0313:
0314:            /**
0315:             * Gets the password used to login to the database.
0316:             * 
0317:             * @return password
0318:             */
0319:            public String getPassword() {
0320:                return vdbPassword;
0321:            }
0322:
0323:            /**
0324:             * Gets the untouched String URL that was passed by the client application
0325:             * 
0326:             * @return value of url.
0327:             */
0328:            public String getUrl() {
0329:                return sequoiaUrl.getUrl();
0330:            }
0331:
0332:            /**
0333:             * Gets the parsed Sequoia URL, including merged properties
0334:             * 
0335:             * @return the parsed Sequoia URL
0336:             */
0337:            SequoiaUrl getSequoiaUrl() {
0338:                return sequoiaUrl;
0339:            }
0340:
0341:            /**
0342:             * Gets the user name used to login to the database.
0343:             * 
0344:             * @return login name
0345:             */
0346:            public String getUserName() {
0347:                return vdbUser;
0348:            }
0349:
0350:            /**
0351:             * Returns the escapeBackslash value.
0352:             * 
0353:             * @return Returns the escapeBackslash.
0354:             */
0355:            public boolean isEscapeBackslash() {
0356:                return escapeBackslash;
0357:            }
0358:
0359:            /**
0360:             * Sets the escapeBackslash value.
0361:             * 
0362:             * @param escapeBackslash The escapeBackslash to set.
0363:             */
0364:            public void setEscapeBackslash(boolean escapeBackslash) {
0365:                this .escapeBackslash = escapeBackslash;
0366:            }
0367:
0368:            /**
0369:             * Returns the escapeSingleQuote value.
0370:             * 
0371:             * @return Returns the escapeSingleQuote.
0372:             */
0373:            public boolean isEscapeSingleQuote() {
0374:                return escapeSingleQuote;
0375:            }
0376:
0377:            /**
0378:             * Sets the escapeSingleQuote value.
0379:             * 
0380:             * @param escapeSingleQuote The escapeSingleQuote to set.
0381:             */
0382:            public void setEscapeSingleQuote(boolean escapeSingleQuote) {
0383:                this .escapeSingleQuote = escapeSingleQuote;
0384:            }
0385:
0386:            /**
0387:             * Sets the escapeCharacter value
0388:             * 
0389:             * @param escapeChar the escapeChar value to set
0390:             */
0391:            public void setEscapeChar(String escapeChar) {
0392:                this .escapeChar = escapeChar;
0393:            }
0394:
0395:            /**
0396:             * @return Returns the escapeChar.
0397:             */
0398:            public String getEscapeChar() {
0399:                return escapeChar;
0400:            }
0401:
0402:            /**
0403:             * Returns the connectionPooling value.
0404:             * 
0405:             * @return Returns the connectionPooling.
0406:             */
0407:            public boolean isConnectionPooling() {
0408:                return connectionPooling;
0409:            }
0410:
0411:            /**
0412:             * Sets the connectionPooling value.
0413:             * 
0414:             * @param connectionPooling The connectionPooling to set.
0415:             */
0416:            public void setConnectionPooling(boolean connectionPooling) {
0417:                this .connectionPooling = connectionPooling;
0418:            }
0419:
0420:            /**
0421:             * Returns the alwaysGetGeneratedKeys value.
0422:             * 
0423:             * @return Returns the alwaysGetGeneratedKeys.
0424:             */
0425:            boolean isAlwaysGettingGeneratedKeys() {
0426:                return alwaysGetGeneratedKeys;
0427:            }
0428:
0429:            //
0430:            // java.sql.Connection implementation
0431:            //
0432:
0433:            /**
0434:             * After this call, <code>getWarnings()</code> returns <code>null</code>
0435:             * until a new call to getWarnings() on this connection.
0436:             * 
0437:             * @exception SQLException if a database access error occurs
0438:             */
0439:            public void clearWarnings() throws SQLException {
0440:                if (!persistentConnection || !retrieveSQLWarnings)
0441:                    // nop
0442:                    return;
0443:                if (isClosed) {
0444:                    // on a closed connection, just reset the warnings
0445:                    // jdbc spec doesn't ask to throw SQLException
0446:                    firstWarning = null;
0447:                    return;
0448:                }
0449:
0450:                try {
0451:                    sendCommand(Commands.ConnectionClearWarnings);
0452:                    socketOutput.writeLong(persistentConnectionId);
0453:                    socketOutput.flush();
0454:                    if (sequoiaUrl.isDebugEnabled())
0455:                        System.out.println("Executing "
0456:                                + getCurrentMethodName());
0457:                    // forget the ack, we just need to know if an exception occured
0458:                    receiveBooleanOrException();
0459:                } catch (SerializableException e) {
0460:                    throw new DriverSQLException(e);
0461:                } catch (IOException e) {
0462:                    try { // Connection failed, try to reconnect and re-send command
0463:                        reconnect();
0464:                        clearWarnings();
0465:                    } catch (DriverSQLException e1) {
0466:                        throw new DriverSQLException(
0467:                                "Connection lost while clearWarnings() and automatic reconnect failed("
0468:                                        + e1 + ")", e1);
0469:                    }
0470:                }
0471:
0472:            }
0473:
0474:            /**
0475:             * Releases the connection. In fact, the connection is marked to be released
0476:             * but will be effectively closed by the <code>ConnectionClosingThread</code>
0477:             * if the connection has not been reused before.
0478:             * 
0479:             * @exception DriverSQLException if an error occurs
0480:             */
0481:            public void close() throws DriverSQLException {
0482:                synchronized (this ) // Wait until other methods/Commands are done
0483:                {
0484:                    // Spec says:
0485:                    // Calling the method close on a Connection object that is already closed
0486:                    // is a no-op.
0487:                    if (isClosed)
0488:                        return;
0489:                    isClosed = true;
0490:                    /*
0491:                     * All JDBC entry points (methods) of this Connection have to
0492:                     * throwSQLExceptionIfClosed(). Relaxed: at least every JDBC method _with
0493:                     * some side-effect_ has to throwSQLExceptionIfClosed(). So now we are
0494:                     * safe and can leave the lock, since they will fail anyway.
0495:                     */
0496:                }
0497:
0498:                if (connectionPooling && !persistentConnection) { // Try to pool the connection for later reuse
0499:                    // Persistent connections are not pooled to free resources right away
0500:                    if (sequoiaUrl.isDebugEnabled())
0501:                        System.out
0502:                                .println("Resetting connection and adding it to the pool");
0503:                    autoCommit = true;
0504:                    mustBeginTransaction = false;
0505:                    readOnly = false;
0506:                    writeExecutedInTransaction = false;
0507:                    isolationLevel = DEFAULT_TRANSACTION_ISOLATION_LEVEL;
0508:                    try {
0509:                        sendCommand(Commands.Reset);
0510:                        socketOutput.flush();
0511:                        if (socketInput != null) {
0512:                            // Wait for the controller to receive the reset, in order to have
0513:                            // an exception thrown if there are no more controllers
0514:                            receiveBooleanOrException();
0515:                        }
0516:                    } catch (Exception ignored) {
0517:                        // Try to reconnect to inform other controllers that we are reseting
0518:                        // this connection. Do it only once to avoid endless loops
0519:                        reconnect();
0520:                        try {
0521:                            sendCommand(Commands.Reset);
0522:                            socketOutput.flush();
0523:                            if (socketInput != null) {
0524:                                // Wait for the controller to receive the reset, in order to have
0525:                                // an exception thrown if there are no more controllers
0526:                                receiveBooleanOrException();
0527:                            }
0528:                        } catch (Exception e) {
0529:                            // Ok, no way to reset connection on the controller side, let's throw
0530:                            // the exception
0531:                            throw new DriverSQLException(
0532:                                    "Error while closing the connection\n"
0533:                                            + e.getLocalizedMessage(), e);
0534:                        }
0535:                    }
0536:
0537:                    // only one (Connection) accessing the pool at a time
0538:                    synchronized (driver.pendingConnectionClosing) {
0539:                        if (!driver.connectionClosingThreadisAlive) { // First connection to close, start a new closing thread
0540:                            if (sequoiaUrl.isDebugEnabled())
0541:                                System.out
0542:                                        .println("Starting a new connection closing thread");
0543:                            ConnectionClosingThread t = new ConnectionClosingThread(
0544:                                    driver);
0545:                            t.start();
0546:                        }
0547:                        // Add to the list
0548:                        driver.pendingConnectionClosing.add(this );
0549:                    }
0550:                } else { // Close connection
0551:                    try {
0552:                        // driver = null; // probably useless since we use now
0553:                        // throwSQLExceptionIfClosed(), but
0554:                        // harmless anyway
0555:                        if (socketOutput != null) {
0556:                            if (sequoiaUrl.isDebugEnabled())
0557:                                System.out.println("Closing connection");
0558:                            sendCommand(Commands.Close);
0559:                            socketOutput.flush();
0560:                            if (socketInput != null) { // Wait for the controller to receive the connection and close the
0561:                                // stream. If we do not wait for the controller ack, the connection
0562:                                // is closed on the controller before the closing is handled which
0563:                                // results in an ugly warning message on the controller side. We are
0564:                                // not in a hurry when closing the connection so let do the things
0565:                                // nicely!
0566:                                receiveBooleanOrException();
0567:                                socketInput.close();
0568:                            }
0569:                            socketOutput.close();
0570:                        }
0571:
0572:                    } catch (Exception ignore) {
0573:                        // we attempt to reconnect to another controller:
0574:                        // since the connection was persistent, controllers
0575:                        // must be informed of the close operation so that
0576:                        // they can clean up their resources properly
0577:                        reconnect();
0578:                        close();
0579:                    }
0580:                }
0581:            }
0582:
0583:            /**
0584:             * Makes all changes made since the previous commit/rollback permanent and
0585:             * releases any database locks currently held by the <code>Connection</code>.
0586:             * This method should only be used when auto-commit has been disabled. (If
0587:             * <code>autoCommit</code>== <code>true</code>, then we throw a
0588:             * DriverSQLException).
0589:             * 
0590:             * @exception DriverSQLException if a database access error occurs or the
0591:             *              connection is in autocommit mode
0592:             * @see Connection#setAutoCommit(boolean)
0593:             */
0594:            public synchronized void commit() throws DriverSQLException {
0595:                throwSQLExceptionIfClosed();
0596:                if (autoCommit) {
0597:                    if (isCommitInAutoCommitAllowed()) {
0598:                        return; // nothing to do
0599:                    } else {
0600:                        throw new DriverSQLException(
0601:                                "Trying to commit a connection in autocommit mode");
0602:                    }
0603:                }
0604:                // Check if we are not committing an empty transaction (not started yet)
0605:                if (mustBeginTransaction)
0606:                    return;
0607:
0608:                doCommit();
0609:            }
0610:
0611:            private void doCommit() throws DriverSQLException {
0612:                try {
0613:                    sendCommand(Commands.Commit);
0614:                    socketOutput.flush();
0615:
0616:                    // Commit acknowledgement
0617:                    long acknowledgedTransactionId = receiveLongOrException();
0618:                    // sanity check
0619:                    if (acknowledgedTransactionId != transactionId) {
0620:                        throw new DriverSQLException(
0621:                                "Protocol error during commit (acknowledge transaction ID = "
0622:                                        + acknowledgedTransactionId
0623:                                        + ", expected transaction ID = "
0624:                                        + transactionId + ")");
0625:                    }
0626:                    mustBeginTransaction = true; // lazy begin
0627:                    writeExecutedInTransaction = false;
0628:                } catch (SerializableException e) {
0629:                    throw new DriverSQLException(e);
0630:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the commit
0631:                    try {
0632:                        // this should resend transactionId (among others)
0633:                        reconnect();
0634:
0635:                        // get an ack
0636:                        long acknowledgedTransactionId = retrieveCommitResult();
0637:                        // sanity check
0638:                        if (acknowledgedTransactionId != transactionId) {
0639:                            throw new DriverSQLException(
0640:                                    "Protocol error during commit (acknowledge transaction ID = "
0641:                                            + acknowledgedTransactionId
0642:                                            + ", expected transaction ID = "
0643:                                            + transactionId + ")");
0644:                        }
0645:                        mustBeginTransaction = true;
0646:                        writeExecutedInTransaction = false;
0647:
0648:                        // The controller will automatically redo the commit if it was not done
0649:                        // earlier so we can safely return here, this is a success.
0650:                        return;
0651:                    } catch (DriverSQLException e1) {
0652:                        throw new DriverSQLException(
0653:                                "Connection lost during commit of transaction '"
0654:                                        + transactionId
0655:
0656:                                        + "' and automatic reconnect failed("
0657:                                        + e1 + ")", e1);
0658:                    }
0659:                }
0660:            }
0661:
0662:            /**
0663:             * Determines whether or not commit should be allowed when autocommit is
0664:             * enabled.
0665:             * 
0666:             * @return true when commit is allowed with autocommit
0667:             */
0668:            private boolean isCommitInAutoCommitAllowed() {
0669:                String allowed = (String) sequoiaUrl.getParameters().get(
0670:                        Driver.ALLOW_COMMIT_WITH_AUTOCOMMIT_PROPERTY);
0671:
0672:                return allowed != null && allowed.toLowerCase().equals("true");
0673:            }
0674:
0675:            /**
0676:             * SQL statements without parameters are normally executed using
0677:             * <code>Statement</code> objects. If the same SQL statement is executed
0678:             * many times, it is more efficient to use a <code>PreparedStatement</code>.
0679:             * The <code>ResultSet</code> will be
0680:             * <code>TYPE_FORWARD_ONLY</cde>/<code>CONCUR_READ_ONLY</code>.
0681:             *    *
0682:             * @return a new <code>Statement</code> object
0683:             * @exception DriverSQLException passed through from the constructor
0684:             */
0685:            public java.sql.Statement createStatement()
0686:                    throws DriverSQLException {
0687:                throwSQLExceptionIfClosed();
0688:                return new Statement(this , driver);
0689:            }
0690:
0691:            /**
0692:             * SQL statements without parameters are normally executed using
0693:             * <code>Statement</code> objects. If the same SQL statement is executed
0694:             * many times, it is more efficient to use a <code>PreparedStatement</code>.
0695:             * 
0696:             * @param resultSetType resultSetType to use
0697:             * @param resultSetConcurrency resultSetConcurrency to use
0698:             * @return a new <code>Statement</code> object
0699:             * @exception SQLException passed through from the constructor
0700:             */
0701:            public java.sql.Statement createStatement(int resultSetType,
0702:                    int resultSetConcurrency) throws SQLException {
0703:                throwSQLExceptionIfClosed();
0704:                Statement s = new Statement(this , driver);
0705:                s.setResultSetType(resultSetType);
0706:                s.setResultSetConcurrency(resultSetConcurrency);
0707:                return s;
0708:            }
0709:
0710:            /**
0711:             * Creates a <code>Statement</code> object that will generate
0712:             * <code>ResultSet</code> objects with the given type, concurrency, and
0713:             * holdability.
0714:             * <p>
0715:             * This method is the same as the <code>createStatement</code> method above,
0716:             * but it allows the default result set type, concurrency, and holdability to
0717:             * be overridden.
0718:             * 
0719:             * @param resultSetType one of the following <code>ResultSet</code>
0720:             *          constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
0721:             *          <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
0722:             *          <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
0723:             * @param resultSetConcurrency one of the following <code>ResultSet</code>
0724:             *          constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
0725:             *          <code>ResultSet.CONCUR_UPDATABLE</code>
0726:             * @param resultSetHoldability one of the following <code>ResultSet</code>
0727:             *          constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
0728:             *          <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
0729:             * @return a new <code>Statement</code> object that will generate
0730:             *         <code>ResultSet</code> objects with the given type, concurrency,
0731:             *         and holdability
0732:             * @exception SQLException if a database access error occurs or the given
0733:             *              parameters are not <code>ResultSet</code> constants
0734:             *              indicating type, concurrency, and holdability
0735:             * @see ResultSet
0736:             * @since JDK 1.4
0737:             */
0738:            public java.sql.Statement createStatement(int resultSetType,
0739:                    int resultSetConcurrency, int resultSetHoldability)
0740:                    throws SQLException {
0741:                throw new NotImplementedException(getCurrentMethodName());
0742:            }
0743:
0744:            /**
0745:             * Gets the current auto-commit state.
0746:             * 
0747:             * @return current state of the auto-commit mode
0748:             * @exception DriverSQLException is connection is closed
0749:             * @see Connection#setAutoCommit
0750:             */
0751:            public boolean getAutoCommit() throws DriverSQLException {
0752:                throwSQLExceptionIfClosed();
0753:                return this .autoCommit;
0754:            }
0755:
0756:            /**
0757:             * A connection's database is able to provide information describing its
0758:             * tables, its supported SQL grammar, its stored procedures, the capabilities
0759:             * of this connection, etc. This information is made available through a
0760:             * DatabaseMetaData object.
0761:             * 
0762:             * @return a <code>DatabaseMetaData</code> object for this connection
0763:             * @exception DriverSQLException if connection is closed
0764:             */
0765:            public java.sql.DatabaseMetaData getMetaData()
0766:                    throws DriverSQLException {
0767:                throwSQLExceptionIfClosed();
0768:                if (metaData == null) {
0769:                    metaData = new DatabaseMetaData(this );
0770:                }
0771:                return metaData;
0772:            }
0773:
0774:            /**
0775:             * Return current catalog name.
0776:             * 
0777:             * @return name of the current <code>VirtualDatabase</code>
0778:             * @throws DriverSQLException if any error occurs
0779:             * @see Connection#getCatalog()
0780:             */
0781:            public synchronized String getCatalog() throws DriverSQLException {
0782:                throwSQLExceptionIfClosed();
0783:                try {
0784:                    sendCommand(Commands.ConnectionGetCatalog);
0785:                    socketOutput.flush();
0786:
0787:                    if (sequoiaUrl.isDebugEnabled())
0788:                        System.out.println("Executing "
0789:                                + getCurrentMethodName());
0790:
0791:                    return receiveStringOrException();
0792:                } catch (SerializableException e) {
0793:                    throw new DriverSQLException(e);
0794:                } catch (IOException e) {
0795:                    try {
0796:                        reconnect();
0797:                        return getCatalog();
0798:                    } catch (DriverSQLException e1) {
0799:                        throw new DriverSQLException(
0800:                                "Connection lost while executing "
0801:                                        + getCurrentMethodName()
0802:                                        + " and automatic reconnect failed ",
0803:                                e1);
0804:                    }
0805:                }
0806:            }
0807:
0808:            /**
0809:             * getCatalogs definition.
0810:             * 
0811:             * @return instace of <code>ResultSet<code>
0812:             * @throws DriverSQLException if fails (include ANY exception that can be thrown in the code)
0813:             */
0814:            public synchronized ResultSet getCatalogs()
0815:                    throws DriverSQLException {
0816:                throwSQLExceptionIfClosed();
0817:                try {
0818:                    sendCommand(Commands.ConnectionGetCatalogs);
0819:                    socketOutput.flush();
0820:
0821:                    if (sequoiaUrl.isDebugEnabled())
0822:                        System.out.println(getCurrentMethodName());
0823:
0824:                    return receiveResultSet(getCurrentMethodName());
0825:                } catch (SerializableException e) {
0826:                    throw new DriverSQLException(e);
0827:                } catch (IOException e) {
0828:                    try {
0829:                        reconnect();
0830:                        return getCatalogs();
0831:                    } catch (DriverSQLException e1) {
0832:                        throw new DriverSQLException(
0833:                                "Connection lost and automatic reconnect failed while executing "
0834:                                        + getCurrentMethodName(), e1);
0835:                    }
0836:                }
0837:            }
0838:
0839:            /**
0840:             * Retrieves the current holdability of <code>ResultSet</code> objects
0841:             * created using this <code>Connection</code> object. If the value was not
0842:             * set using setHoldability(), the default value of the database is returned.
0843:             * 
0844:             * @return the holdability, one of
0845:             *         <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
0846:             *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
0847:             * @throws SQLException if a database access occurs
0848:             * @see #setHoldability
0849:             * @see ResultSet
0850:             * @since JDK 1.4
0851:             */
0852:            public int getHoldability() throws SQLException {
0853:                if (holdability == HOLDABILITY_NOT_SET)
0854:                    holdability = getMetaData().getResultSetHoldability();
0855:                return holdability;
0856:            }
0857:
0858:            /**
0859:             * Gets this Connection's current transaction isolation mode. If the
0860:             * transaction isolation has not been set using setTransactionIsolation, this
0861:             * method will return by default
0862:             * java.sql.Connection.TRANSACTION_READ_UNCOMMITTED whatever transaction
0863:             * isolation is really used by the cluster nodes. If you want to enfore
0864:             * TRANSACTION_READ_UNCOMMITTED, you have to explicitely call
0865:             * setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED)
0866:             * 
0867:             * @return the current <code>TRANSACTION_*</code> mode value
0868:             * @exception DriverSQLException if a database access error occurs
0869:             * @see #setTransactionIsolation(int)
0870:             */
0871:            public int getTransactionIsolation() throws DriverSQLException {
0872:                throwSQLExceptionIfClosed();
0873:                // Warning, here we assume that if no transaction isolation is set the
0874:                // database will provide READ_UNCOMMITED.
0875:                if (isolationLevel == DEFAULT_TRANSACTION_ISOLATION_LEVEL)
0876:                    return driver.getDefaultTransactionIsolationLevel();
0877:                return isolationLevel;
0878:            }
0879:
0880:            /**
0881:             * Sequoia does NOT support type map.
0882:             * 
0883:             * @return an exception
0884:             * @exception SQLException not supported
0885:             */
0886:            public java.util.Map getTypeMap() throws SQLException {
0887:                throw new NotImplementedException(getCurrentMethodName());
0888:            }
0889:
0890:            /**
0891:             * Returns the first warning reported by calls on this connection. Subsequent
0892:             * warnings will be chained to this SQLWarning<br>
0893:             * <B>Note: </B> If the 'persistent connections' option is set to false, this
0894:             * function will always return null.
0895:             * 
0896:             * @return the first SQLWarning or null
0897:             * @exception DriverSQLException if a database access error occurs or this
0898:             *              method is called on a closed connection
0899:             */
0900:            public SQLWarning getWarnings() throws DriverSQLException {
0901:                throwSQLExceptionIfClosed();
0902:                if (!persistentConnection || !retrieveSQLWarnings)
0903:                    return firstWarning;
0904:
0905:                try {
0906:                    sendCommand(Commands.ConnectionGetWarnings);
0907:                    socketOutput.writeLong(persistentConnectionId);
0908:                    socketOutput.flush();
0909:                    if (sequoiaUrl.isDebugEnabled())
0910:                        System.out.println("Executing "
0911:                                + getCurrentMethodName());
0912:                    return receiveSQLWarnings();
0913:                } catch (SerializableException e) {
0914:                    throw new DriverSQLException(e);
0915:                } catch (IOException e) {
0916:                    try { // Connection failed, try to reconnect and re-send command
0917:                        reconnect();
0918:                        return getWarnings();
0919:                    } catch (DriverSQLException e1) {
0920:                        throw new DriverSQLException(
0921:                                "Connection lost while getting SQL Warnings and automatic reconnect failed("
0922:                                        + e1 + ")", e1);
0923:                    }
0924:                }
0925:            }
0926:
0927:            /**
0928:             * Returns <code>true</code> if the connection has been closed by the user
0929:             * (but Sequoia may leave it open underneath, unknown to the user).
0930:             * 
0931:             * @return <code>true</code> if connection has never been opened or
0932:             *         <code>close()</code> has been called
0933:             */
0934:            public boolean isClosed() {
0935:                return isClosed;
0936:            }
0937:
0938:            /**
0939:             * Tests to see if the connection is in read only Mode. Note that we cannot
0940:             * really put the database in read only mode, but we pretend we can by
0941:             * returning the value of the <code>readOnly</code> flag.
0942:             * 
0943:             * @return <code>true</code> if the connection is read only
0944:             */
0945:            public boolean isReadOnly() {
0946:                return readOnly;
0947:            }
0948:
0949:            /**
0950:             * As we can't know for sure which database will execute this request (now or
0951:             * later), we can't translate it in the native query language of the
0952:             * underlying DBMS. Therefore the query is returned unchanged.
0953:             * 
0954:             * @param query the query to change
0955:             * @return the original query
0956:             */
0957:            public String nativeSQL(String query) {
0958:                return query;
0959:            }
0960:
0961:            /**
0962:             * A SQL statement with or without <code>IN</code> parameters can be
0963:             * pre-compiled and stored in a PreparedStatement object. This object can then
0964:             * be used to efficiently execute this statement multiple times.
0965:             * 
0966:             * @param sql a SQL statement that may contain one or more '?' IN * parameter
0967:             *          placeholders
0968:             * @return a new <code>PreparedStatement</code> object containing the
0969:             *         pre-compiled statement.
0970:             * @exception SQLException if a database access error occurs.
0971:             */
0972:            public java.sql.PreparedStatement prepareStatement(String sql)
0973:                    throws SQLException {
0974:                throwSQLExceptionIfClosed();
0975:                return new PreparedStatement(this , sql, driver);
0976:            }
0977:
0978:            /**
0979:             * Creates a default <code>PreparedStatement</code> object that has the
0980:             * capability to retrieve auto-generated keys. The given constant tells the
0981:             * driver whether it should make auto-generated keys available for retrieval.
0982:             * This parameter is ignored if the SQL statement is not an
0983:             * <code>INSERT</code> statement.
0984:             * <p>
0985:             * <b>Note: </b> This method is optimized for handling parametric SQL
0986:             * statements that benefit from precompilation. If the driver supports
0987:             * precompilation, the method <code>prepareStatement</code> will send the
0988:             * statement to the database for precompilation. Some drivers may not support
0989:             * precompilation. In this case, the statement may not be sent to the database
0990:             * until the <code>PreparedStatement</code> object is executed. This has no
0991:             * direct effect on users; however, it does affect which methods throw certain
0992:             * SQLExceptions.
0993:             * <p>
0994:             * Result sets created using the returned <code>PreparedStatement</code>
0995:             * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
0996:             * concurrency level of <code>CONCUR_READ_ONLY</code>.
0997:             * 
0998:             * @param sql an SQL statement that may contain one or more '?' IN parameter
0999:             *          placeholders
1000:             * @param autoGeneratedKeys a flag indicating whether auto-generated keys
1001:             *          should be returned; one of
1002:             *          <code>Statement.RETURN_GENERATED_KEYS</code> or
1003:             *          <code>Statement.NO_GENERATED_KEYS</code>
1004:             * @return a new <code>PreparedStatement</code> object, containing the
1005:             *         pre-compiled SQL statement, that will have the capability of
1006:             *         returning auto-generated keys
1007:             * @exception SQLException if a database access error occurs or the given
1008:             *              parameter is not a <code>Statement</code> constant
1009:             *              indicating whether auto-generated keys should be returned
1010:             * @since JDK 1.4
1011:             */
1012:            public java.sql.PreparedStatement prepareStatement(String sql,
1013:                    int autoGeneratedKeys) throws SQLException {
1014:                throwSQLExceptionIfClosed();
1015:                PreparedStatement ps = new PreparedStatement(this , sql, driver,
1016:                        autoGeneratedKeys);
1017:                return ps;
1018:            }
1019:
1020:            /**
1021:             * Creates a default <code>PreparedStatement</code> object capable of
1022:             * returning the auto-generated keys designated by the given array. This array
1023:             * contains the indexes of the columns in the target table that contain the
1024:             * auto-generated keys that should be made available. This array is ignored if
1025:             * the SQL statement is not an <code>INSERT</code> statement.
1026:             * <p>
1027:             * An SQL statement with or without IN parameters can be pre-compiled and
1028:             * stored in a <code>PreparedStatement</code> object. This object can then
1029:             * be used to efficiently execute this statement multiple times.
1030:             * <p>
1031:             * <b>Note: </b> This method is optimized for handling parametric SQL
1032:             * statements that benefit from precompilation. If the driver supports
1033:             * precompilation, the method <code>prepareStatement</code> will send the
1034:             * statement to the database for precompilation. Some drivers may not support
1035:             * precompilation. In this case, the statement may not be sent to the database
1036:             * until the <code>PreparedStatement</code> object is executed. This has no
1037:             * direct effect on users; however, it does affect which methods throw certain
1038:             * SQLExceptions.
1039:             * <p>
1040:             * Result sets created using the returned <code>PreparedStatement</code>
1041:             * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
1042:             * concurrency level of <code>CONCUR_READ_ONLY</code>.
1043:             * 
1044:             * @param sql an SQL statement that may contain one or more '?' IN parameter
1045:             *          placeholders
1046:             * @param columnIndexes an array of column indexes indicating the columns that
1047:             *          should be returned from the inserted row or rows
1048:             * @return a new <code>PreparedStatement</code> object, containing the
1049:             *         pre-compiled statement, that is capable of returning the
1050:             *         auto-generated keys designated by the given array of column indexes
1051:             * @exception SQLException if a database access error occurs
1052:             * @since JDK 1.4
1053:             */
1054:            public java.sql.PreparedStatement prepareStatement(String sql,
1055:                    int[] columnIndexes) throws SQLException {
1056:                throwSQLExceptionIfClosed();
1057:                PreparedStatement ps = new PreparedStatement(this , sql, driver,
1058:                        PreparedStatement.RETURN_GENERATED_KEYS);
1059:                return ps;
1060:            }
1061:
1062:            /**
1063:             * Creates a default <code>PreparedStatement</code> object capable of
1064:             * returning the auto-generated keys designated by the given array. This array
1065:             * contains the names of the columns in the target table that contain the
1066:             * auto-generated keys that should be returned. This array is ignored if the
1067:             * SQL statement is not an <code>INSERT</code> statement.
1068:             * <p>
1069:             * An SQL statement with or without IN parameters can be pre-compiled and
1070:             * stored in a <code>PreparedStatement</code> object. This object can then
1071:             * be used to efficiently execute this statement multiple times.
1072:             * <p>
1073:             * <b>Note: </b> This method is optimized for handling parametric SQL
1074:             * statements that benefit from precompilation. If the driver supports
1075:             * precompilation, the method <code>prepareStatement</code> will send the
1076:             * statement to the database for precompilation. Some drivers may not support
1077:             * precompilation. In this case, the statement may not be sent to the database
1078:             * until the <code>PreparedStatement</code> object is executed. This has no
1079:             * direct effect on users; however, it does affect which methods throw certain
1080:             * <code>SQLExceptions</code>.
1081:             * <p>
1082:             * Result sets created using the returned <code>PreparedStatement</code>
1083:             * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a
1084:             * concurrency level of <code>CONCUR_READ_ONLY</code>.
1085:             * 
1086:             * @param sql an SQL statement that may contain one or more '?' IN parameter
1087:             *          placeholders
1088:             * @param columnNames an array of column names indicating the columns that
1089:             *          should be returned from the inserted row or rows
1090:             * @return a new <code>PreparedStatement</code> object, containing the
1091:             *         pre-compiled statement, that is capable of returning the
1092:             *         auto-generated keys designated by the given array of column names
1093:             * @exception SQLException if a database access error occurs
1094:             * @since JDK 1.4
1095:             */
1096:            public java.sql.PreparedStatement prepareStatement(String sql,
1097:                    String[] columnNames) throws SQLException {
1098:                throwSQLExceptionIfClosed();
1099:                PreparedStatement ps = new PreparedStatement(this , sql, driver,
1100:                        PreparedStatement.RETURN_GENERATED_KEYS);
1101:                return ps;
1102:            }
1103:
1104:            /**
1105:             * A SQL statement with or without IN parameters can be pre-compiled and
1106:             * stored in a <code>PreparedStatement</code> object. This object can then
1107:             * be used to efficiently execute this statement multiple times.
1108:             * 
1109:             * @param sql a SQL statement that may contain one or more '?' IN
1110:             * @param resultSetType <code>ResultSetType</code> to use
1111:             * @param resultSetConcurrency <code>ResultSetConcurrency</code> to use
1112:             * @return a new <code>PreparedStatement</code> object
1113:             * @exception SQLException passed through from the constructor
1114:             */
1115:            public java.sql.PreparedStatement prepareStatement(String sql,
1116:                    int resultSetType, int resultSetConcurrency)
1117:                    throws SQLException {
1118:                throwSQLExceptionIfClosed();
1119:                PreparedStatement s = new PreparedStatement(this , sql, driver);
1120:                s.setResultSetType(resultSetType);
1121:                s.setResultSetConcurrency(resultSetConcurrency);
1122:                return s;
1123:            }
1124:
1125:            /**
1126:             * Creates a <code>PreparedStatement</code> object that will generate
1127:             * <code>ResultSet</code> objects with the given type, concurrency, and
1128:             * holdability.
1129:             * <p>
1130:             * This method is the same as the <code>prepareStatement</code> method
1131:             * above, but it allows the default result set type, concurrency, and
1132:             * holdability to be overridden.
1133:             * 
1134:             * @param sql a <code>String</code> object that is the SQL statement to be
1135:             *          sent to the database; may contain one or more ? IN parameters
1136:             * @param resultSetType one of the following <code>ResultSet</code>
1137:             *          constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
1138:             *          <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
1139:             *          <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
1140:             * @param resultSetConcurrency one of the following <code>ResultSet</code>
1141:             *          constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
1142:             *          <code>ResultSet.CONCUR_UPDATABLE</code>
1143:             * @param resultSetHoldability one of the following <code>ResultSet</code>
1144:             *          constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1145:             *          <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1146:             * @return a new <code>PreparedStatement</code> object, containing the
1147:             *         pre-compiled SQL statement, that will generate
1148:             *         <code>ResultSet</code> objects with the given type, concurrency,
1149:             *         and holdability
1150:             * @exception SQLException if a database access error occurs or the given
1151:             *              parameters are not <code>ResultSet</code> constants
1152:             *              indicating type, concurrency, and holdability
1153:             * @see ResultSet
1154:             * @since JDK 1.4
1155:             */
1156:            public java.sql.PreparedStatement prepareStatement(String sql,
1157:                    int resultSetType, int resultSetConcurrency,
1158:                    int resultSetHoldability) throws SQLException {
1159:                throwSQLExceptionIfClosed();
1160:                PreparedStatement ps = new PreparedStatement(this , sql, driver);
1161:                ps.setResultSetType(resultSetType);
1162:                ps.setResultSetConcurrency(resultSetConcurrency);
1163:                setHoldability(resultSetHoldability);
1164:                return ps;
1165:            }
1166:
1167:            /**
1168:             * Creates a CallableStatement that contains sql and produces a ResultSet that
1169:             * is TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY.
1170:             * 
1171:             * @param sql SQL request
1172:             * @return a CallableStatement
1173:             * @exception SQLException not supported
1174:             */
1175:            public java.sql.CallableStatement prepareCall(String sql)
1176:                    throws SQLException {
1177:                throwSQLExceptionIfClosed();
1178:                return prepareCall(sql,
1179:                        java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,
1180:                        java.sql.ResultSet.CONCUR_READ_ONLY);
1181:            }
1182:
1183:            /**
1184:             * @see java.sql.Connection#prepareCall(java.lang.String, int, int)
1185:             */
1186:            public java.sql.CallableStatement prepareCall(String sql,
1187:                    int resultSetType, int resultSetConcurrency)
1188:                    throws SQLException {
1189:                throwSQLExceptionIfClosed();
1190:                CallableStatement c = new CallableStatement(this , sql, driver);
1191:                c.setResultSetType(resultSetType);
1192:                c.setResultSetConcurrency(resultSetConcurrency);
1193:                return c;
1194:            }
1195:
1196:            /**
1197:             * Creates a <code>CallableStatement</code> object that will generate
1198:             * <code>ResultSet</code> objects with the given type and concurrency. This
1199:             * method is the same as the <code>prepareCall</code> method above, but it
1200:             * allows the default result set type, result set concurrency type and
1201:             * holdability to be overridden.
1202:             * 
1203:             * @param sql a <code>String</code> object that is the SQL statement to be
1204:             *          sent to the database; may contain on or more ? parameters
1205:             * @param resultSetType one of the following <code>ResultSet</code>
1206:             *          constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
1207:             *          <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
1208:             *          <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
1209:             * @param resultSetConcurrency one of the following <code>ResultSet</code>
1210:             *          constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
1211:             *          <code>ResultSet.CONCUR_UPDATABLE</code>
1212:             * @param resultSetHoldability one of the following <code>ResultSet</code>
1213:             *          constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1214:             *          <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1215:             * @return a new <code>CallableStatement</code> object, containing the
1216:             *         pre-compiled SQL statement, that will generate
1217:             *         <code>ResultSet</code> objects with the given type, concurrency,
1218:             *         and holdability
1219:             * @exception SQLException if a database access error occurs or the given
1220:             *              parameters are not <code>ResultSet</code> constants
1221:             *              indicating type, concurrency, and holdability
1222:             * @see ResultSet
1223:             * @since JDK 1.4
1224:             */
1225:            public java.sql.CallableStatement prepareCall(String sql,
1226:                    int resultSetType, int resultSetConcurrency,
1227:                    int resultSetHoldability) throws SQLException {
1228:                throwSQLExceptionIfClosed();
1229:                CallableStatement cs = new CallableStatement(this , sql, driver);
1230:                cs.setResultSetType(resultSetType);
1231:                cs.setResultSetConcurrency(resultSetConcurrency);
1232:                setHoldability(resultSetHoldability);
1233:                return cs;
1234:            }
1235:
1236:            /**
1237:             * Removes the given <code>Savepoint</code> object from the current
1238:             * transaction. Any reference to the savepoint after it have been removed will
1239:             * cause an <code>SQLException</code> to be thrown.
1240:             * 
1241:             * @param savepoint the <code>Savepoint</code> object to be removed
1242:             * @exception DriverSQLException if a database access error occurs or the
1243:             *              given <code>Savepoint</code> object is not a valid savepoint
1244:             *              in the current transaction
1245:             * @since JDK 1.4
1246:             */
1247:            public void releaseSavepoint(Savepoint savepoint)
1248:                    throws DriverSQLException {
1249:                throwSQLExceptionIfClosed();
1250:                if (savepoint == null)
1251:                    throw new DriverSQLException("Savepoint cannot be null");
1252:
1253:                if (autoCommit)
1254:                    throw new DriverSQLException(
1255:                            "Trying to release a savepoint in autocommit mode");
1256:
1257:                if (driver == null)
1258:                    throw new DriverSQLException(
1259:                            "No driver to release a savepoint");
1260:
1261:                try {
1262:                    sendCommand(Commands.ReleaseSavepoint);
1263:                    savepointOnStream(savepoint);
1264:                    socketOutput.flush();
1265:
1266:                    this .receiveBooleanOrException();
1267:                } catch (SerializableException e) {
1268:                    throw new DriverSQLException(e);
1269:                } catch (IOException e) {
1270:                    try {
1271:                        // Connection failed, try to reconnect and release the savepoint again
1272:                        reconnect();
1273:                        boolean done = retrieveReleaseSavepoint(savepoint);
1274:                        if (!done) {
1275:                            releaseSavepoint(savepoint);
1276:                        }
1277:                    } catch (DriverSQLException e1) {
1278:                        throw new DriverSQLException(
1279:                                "Connection lost while releasing savepoint '"
1280:                                        + savepoint
1281:                                        + "' and automatic reconnect failed("
1282:                                        + e1 + ")", e1);
1283:                    }
1284:                }
1285:            }
1286:
1287:            /**
1288:             * Drops all changes made since the previous commit/rollback and releases any
1289:             * database locks currently held by this connection. If the connection was in
1290:             * autocommit mode, we throw a DriverSQLException.
1291:             * 
1292:             * @exception DriverSQLException if a database access error occurs or the
1293:             *              connection is in autocommit mode
1294:             * @see Connection#commit()
1295:             */
1296:            public synchronized void rollback() throws DriverSQLException {
1297:                throwSQLExceptionIfClosed();
1298:                if (autoCommit)
1299:                    throw new DriverSQLException(
1300:                            "Trying to rollback a connection in autocommit mode");
1301:
1302:                // Check if we are not rollbacking an empty transaction (not started yet)
1303:                if (mustBeginTransaction)
1304:                    return;
1305:
1306:                try {
1307:                    sendCommand(Commands.Rollback);
1308:                    socketOutput.flush();
1309:
1310:                    // rollback acknowledgement
1311:                    long acknowledgedTransactionId = receiveLongOrException();
1312:                    if (acknowledgedTransactionId != transactionId) {
1313:                        throw new DriverSQLException(
1314:                                "Protocol error during rollback (acknowledge transaction ID = "
1315:                                        + acknowledgedTransactionId
1316:                                        + ", expected transaction ID = "
1317:                                        + transactionId + ")");
1318:                    }
1319:                    mustBeginTransaction = true;
1320:                    writeExecutedInTransaction = false;
1321:                } catch (SerializableException e) {
1322:                    throw new DriverSQLException(e);
1323:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the rollback
1324:                    try {
1325:                        reconnect();
1326:
1327:                        long acknowledgedTransactionId = retrieveRollbackResult();
1328:                        if (acknowledgedTransactionId != transactionId) {
1329:                            throw new DriverSQLException(
1330:                                    "Protocol error during rollback failover (acknowledge transaction ID = "
1331:                                            + acknowledgedTransactionId
1332:                                            + ", expected transaction ID = "
1333:                                            + transactionId + ")");
1334:                        }
1335:                        mustBeginTransaction = true;
1336:
1337:                        // The controller will automatically redo the rollback if it was not
1338:                        // done earlier so we can safely return here, this is a success.
1339:                        return;
1340:                    } catch (DriverSQLException e1) {
1341:                        throw new DriverSQLException(
1342:                                "Connection lost during rollback of transaction '"
1343:                                        + transactionId
1344:
1345:                                        + "' and automatic reconnect failed("
1346:                                        + e1 + ")", e1);
1347:                    }
1348:                }
1349:            }
1350:
1351:            /**
1352:             * Undoes all changes made after the given <code>Savepoint</code> object was
1353:             * set.
1354:             * <p>
1355:             * This method should be used only when auto-commit has been disabled.
1356:             * 
1357:             * @param savepoint the <code>Savepoint</code> object to roll back to
1358:             * @exception DriverSQLException if a database access error occurs, the
1359:             *              <code>Savepoint</code> object is no longer valid, or this
1360:             *              <code>Connection</code> object is currently in auto-commit
1361:             *              mode
1362:             * @see Savepoint
1363:             * @see #rollback()
1364:             * @since JDK 1.4
1365:             */
1366:            public void rollback(Savepoint savepoint) throws DriverSQLException {
1367:                throwSQLExceptionIfClosed();
1368:                if (savepoint == null)
1369:                    throw new DriverSQLException("Savepoint cannot be null");
1370:
1371:                if (autoCommit)
1372:                    throw new DriverSQLException(
1373:                            "Trying to rollback to a savepoint in autocommit mode");
1374:
1375:                if (driver == null)
1376:                    throw new DriverSQLException(
1377:                            "No driver to rollback to savepoint");
1378:
1379:                try {
1380:                    sendCommand(Commands.RollbackToSavepoint);
1381:                    savepointOnStream(savepoint);
1382:                    socketOutput.flush();
1383:
1384:                    this .receiveBooleanOrException();
1385:                } catch (SerializableException e) {
1386:                    throw new DriverSQLException(e);
1387:                } catch (IOException e) {
1388:                    try {
1389:                        // Connection failed, try to reconnect and rollback again if checkpoint
1390:                        // still exists
1391:                        reconnect();
1392:                        boolean isCheckpointRemoved = retrieveReleaseSavepoint(savepoint);
1393:                        if (!isCheckpointRemoved)
1394:                            rollback(savepoint);
1395:                    } catch (DriverSQLException e1) {
1396:                        throw new DriverSQLException(
1397:                                "Connection lost while rollbacking to savepoint '"
1398:                                        + savepoint
1399:                                        + "' and automatic reconnect failed("
1400:                                        + e1 + ")", e1);
1401:                    }
1402:                }
1403:            }
1404:
1405:            private void begin() throws DriverSQLException, ProtocolException {
1406:                try {
1407:                    sendCommand(Commands.Begin);
1408:                    socketOutput.flush();
1409:
1410:                    transactionId = receiveLongOrException();
1411:
1412:                    if (sequoiaUrl.isDebugEnabled())
1413:                        System.out.println("Transaction " + transactionId
1414:                                + " has been started");
1415:                } catch (SerializableException e) {
1416:                    throw new DriverSQLException(e);
1417:                } catch (IOException e) {
1418:                    // Connection failed, try to reconnect and re-exec the query
1419:                    if (sequoiaUrl.isInfoEnabled())
1420:                        System.out
1421:                                .println("I/O Error while trying to disable autocommit\n"
1422:                                        + e.getLocalizedMessage());
1423:                    reconnect();
1424:                    begin();
1425:                }
1426:            }
1427:
1428:            /**
1429:             * To keep track of active transactions, sequoia uses the old BEGIN modeless
1430:             * model. Backend's connections on the controller are always maintained/reset
1431:             * in autocommit mode = true, except of course when in the middle of an active
1432:             * transaction. So part of our job here is to translate the new ODBC/JDBC
1433:             * autoCommit mode concept to the old BEGIN model.
1434:             * 
1435:             * @see Commands#SetAutoCommit
1436:             * @see java.sql.Connection#setAutoCommit(boolean)
1437:             * @param autoCommitArg <code>true</code> enables auto-commit;
1438:             *          <code>false</code> disables it
1439:             * @exception DriverSQLException if a database access error occurs
1440:             * @throws DriverIOException if an IO error occured with the controller
1441:             */
1442:            public synchronized void setAutoCommit(boolean autoCommitArg)
1443:                    throws DriverSQLException, DriverIOException {
1444:                throwSQLExceptionIfClosed();
1445:
1446:                // Do nothing if already in the right state
1447:                if (this .autoCommit == autoCommitArg)
1448:                    return;
1449:
1450:                // true -> false (send nothing, lazy begin)
1451:                if (this .autoCommit) {
1452:                    this .autoCommit = false;
1453:                    this .mustBeginTransaction = true;
1454:                    return;
1455:                }
1456:
1457:                // false -> true
1458:                if (mustBeginTransaction) { // Transaction has NOT yet begun
1459:                    // Just cancel the (lazy, not yet done) begin
1460:                    mustBeginTransaction = false;
1461:                    this .autoCommit = true;
1462:                    return;
1463:                } else {
1464:                    if (sequoiaUrl.isDebugEnabled())
1465:                        System.out
1466:                                .println("Setting connection in autocommit mode");
1467:                    doCommit();
1468:                    this .autoCommit = true;
1469:                }
1470:            }
1471:
1472:            /**
1473:             * Change the current catalog
1474:             * 
1475:             * @param catalog a <code>String</code> value
1476:             * @exception SQLException if fails or if catalog name is invalid
1477:             */
1478:            public synchronized void setCatalog(String catalog)
1479:                    throws SQLException {
1480:                throwSQLExceptionIfClosed();
1481:                if (catalog == null)
1482:                    throw new DriverSQLException("Invalid Catalog");
1483:                sequoiaUrl.setUrl(driver.changeDatabaseName(
1484:                        sequoiaUrl.getUrl(), catalog));
1485:
1486:                try {
1487:                    sendCommand(Commands.ConnectionSetCatalog);
1488:                    socketOutput.writeLongUTF(catalog);
1489:                    socketOutput.flush();
1490:
1491:                    if (sequoiaUrl.isDebugEnabled())
1492:                        System.out.println("Executing "
1493:                                + getCurrentMethodName() + " with catalog '"
1494:                                + catalog + "'");
1495:
1496:                    if (!receiveBooleanOrException())
1497:                        throw new DriverSQLException("Invalid Catalog");
1498:
1499:                } catch (SerializableException e) {
1500:                    throw new DriverSQLException(e);
1501:                } catch (IOException e) {
1502:                    try {
1503:                        // Connection failed, try to reconnect and re-set the catalog
1504:                        reconnect();
1505:                        setCatalog(catalog);
1506:                    } catch (DriverSQLException e1) {
1507:                        throw new DriverSQLException(
1508:                                "Connection lost while setting the catalog '"
1509:                                        + catalog
1510:                                        + "' and automatic reconnect failed("
1511:                                        + e1 + ")", e1);
1512:                    }
1513:                }
1514:            }
1515:
1516:            /**
1517:             * Changes the holdability of <code>ResultSet</code> objects created using
1518:             * this <code>Connection</code> object to the given holdability.
1519:             * 
1520:             * @param holdability a <code>ResultSet</code> holdability constant; one of
1521:             *          <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
1522:             *          <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
1523:             * @throws SQLException if a database access occurs, the given parameter is
1524:             *           not a <code>ResultSet</code> constant indicating holdability,
1525:             *           or the given holdability is not supported
1526:             * @see #getHoldability
1527:             * @see ResultSet
1528:             * @since JDK 1.4
1529:             */
1530:            public void setHoldability(int holdability) throws SQLException {
1531:                if ((holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT)
1532:                        && (holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT))
1533:                    throw new SQLException("Invalid holdaibility value "
1534:                            + holdability);
1535:                this .holdability = holdability;
1536:            }
1537:
1538:            /**
1539:             * You can put a connection in read-only mode as a hint to enable database
1540:             * optimizations
1541:             * 
1542:             * @param readOnly <code>true</code> enables read-only mode;
1543:             *          <code>false</code> disables it
1544:             * @exception DriverSQLException if a database access error occurs
1545:             */
1546:            public void setReadOnly(boolean readOnly) throws DriverSQLException {
1547:                throwSQLExceptionIfClosed();
1548:
1549:                try {
1550:                    sendCommand(Commands.SetReadOnly);
1551:                    socketOutput.writeBoolean(readOnly);
1552:                    socketOutput.flush();
1553:
1554:                    if (sequoiaUrl.isDebugEnabled())
1555:                        System.out.println("Setting connection to read-only="
1556:                                + readOnly);
1557:
1558:                    receiveBooleanOrException();
1559:                    // Success
1560:                    this .readOnly = readOnly;
1561:                    return;
1562:
1563:                } catch (SerializableException e) {
1564:                    throw new DriverSQLException(e);
1565:                } catch (IOException ioe) {
1566:                    try {
1567:                        // Connection failed, try to reconnect and re-set the transaction
1568:                        // isolation level
1569:                        reconnect();
1570:                        setReadOnly(readOnly);
1571:                    } catch (DriverSQLException e1) {
1572:                        throw new DriverSQLException(
1573:                                "Connection lost while setting the connection to read-only="
1574:                                        + readOnly
1575:                                        + " and automatic reconnect failed("
1576:                                        + e1 + ")", e1);
1577:                    }
1578:                }
1579:            }
1580:
1581:            private static final int SAVEPOINT_NOT_SET = -1;
1582:
1583:            /**
1584:             * Creates an unnamed savepoint in the current transaction and returns the new
1585:             * <code>Savepoint</code> object that represents it.
1586:             * 
1587:             * @return the new <code>Savepoint</code> object
1588:             * @exception DriverSQLException if a database access error occurs or this
1589:             *              <code>Connection</code> object is currently in auto-commit
1590:             *              mode
1591:             * @see Savepoint
1592:             * @since JDK 1.4
1593:             */
1594:            public Savepoint setSavepoint() throws DriverSQLException {
1595:                throwSQLExceptionIfClosed();
1596:                beginTransactionIfNeeded();
1597:                if (autoCommit)
1598:                    throw new DriverSQLException(
1599:                            "Trying to set a savepoint in autocommit mode");
1600:
1601:                if (driver == null)
1602:                    throw new DriverSQLException("No driver to set a savepoint");
1603:
1604:                int savepointId = SAVEPOINT_NOT_SET;
1605:                try {
1606:                    sendCommand(Commands.SetUnnamedSavepoint);
1607:                    socketOutput.flush();
1608:
1609:                    savepointId = receiveIntOrException();
1610:                    return new org.continuent.sequoia.driver.Savepoint(
1611:                            savepointId);
1612:                } catch (SerializableException e) {
1613:                    throw new DriverSQLException(e);
1614:                } catch (IOException ioe) {
1615:                    try {
1616:                        // Connection failed, try to reconnect and re-set the savepoint if it
1617:                        // was not set before the failure
1618:                        reconnect();
1619:                        org.continuent.sequoia.driver.Savepoint savepoint = new org.continuent.sequoia.driver.Savepoint(
1620:                                savepointId);
1621:                        boolean checkpointDoesNotExit = (savepointId == SAVEPOINT_NOT_SET)
1622:                                || retrieveReleaseSavepoint(savepoint);
1623:                        if (checkpointDoesNotExit)
1624:                            return this .setSavepoint(); // retry, did not work the first time
1625:                        else
1626:                            return savepoint; // ok, already set
1627:                    } catch (DriverSQLException e1) {
1628:                        throw new DriverSQLException(
1629:                                "Connection lost while setting an unnamed savepoint and automatic reconnect failed("
1630:                                        + e1 + ")", e1);
1631:                    }
1632:                }
1633:            }
1634:
1635:            /**
1636:             * Creates a savepoint with the given name in the current transaction and
1637:             * returns the new <code>Savepoint</code> object that represents it.
1638:             * 
1639:             * @param name a <code>String</code> containing the name of the savepoint
1640:             * @return the new <code>Savepoint</code> object
1641:             * @exception DriverSQLException if a database access error occurs or this
1642:             *              <code>Connection</code> object is currently in auto-commit
1643:             *              mode
1644:             * @see Savepoint
1645:             * @since JDK 1.4
1646:             */
1647:            public Savepoint setSavepoint(String name)
1648:                    throws DriverSQLException {
1649:                throwSQLExceptionIfClosed();
1650:                beginTransactionIfNeeded();
1651:                if (name == null)
1652:                    throw new IllegalArgumentException(
1653:                            "Savepoint name cannot be null");
1654:
1655:                if (autoCommit)
1656:                    throw new DriverSQLException(
1657:                            "Trying to set a savepoint in autocommit mode");
1658:
1659:                if (driver == null)
1660:                    throw new DriverSQLException("No driver to set a savepoint");
1661:
1662:                try {
1663:                    sendCommand(Commands.SetNamedSavepoint);
1664:                    socketOutput.writeLongUTF(name);
1665:                    socketOutput.flush();
1666:
1667:                    this .receiveBooleanOrException();
1668:                    return new org.continuent.sequoia.driver.Savepoint(name);
1669:                } catch (SerializableException se) {
1670:                    throw new DriverSQLException(se);
1671:                } catch (IOException e) {
1672:                    try {
1673:                        // Connection failed, try to reconnect and re-set the savepoint if it
1674:                        // was not set before the failure
1675:                        reconnect();
1676:                        org.continuent.sequoia.driver.Savepoint savepoint = new org.continuent.sequoia.driver.Savepoint(
1677:                                name);
1678:                        boolean checkpointDoesNotExit = retrieveReleaseSavepoint(savepoint);
1679:                        if (checkpointDoesNotExit)
1680:                            return setSavepoint(name);
1681:                        else
1682:                            return savepoint;
1683:                    } catch (DriverSQLException e1) {
1684:                        throw new DriverSQLException(
1685:                                "Connection lost while setting the savepoint '"
1686:                                        + name
1687:                                        + "' and automatic reconnect failed("
1688:                                        + e1 + ")", e1);
1689:                    }
1690:                }
1691:            }
1692:
1693:            /**
1694:             * You can call this method to try to change the transaction isolation level
1695:             * using one of the TRANSACTION_* values.
1696:             * <p>
1697:             * <B>Note: </B> this method cannot be called while in the middle of a
1698:             * transaction. The JDBC spec says it should trigger a commit. We should
1699:             * probably let the backend handle this, not trying to add our own complexity.
1700:             * 
1701:             * @param level one of the TRANSACTION_* isolation values with * the exception
1702:             *          of TRANSACTION_NONE; some databases may * not support other values
1703:             * @exception DriverSQLException if a database access error occurs
1704:             * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
1705:             */
1706:            public synchronized void setTransactionIsolation(int level)
1707:                    throws DriverSQLException {
1708:                throwSQLExceptionIfClosed();
1709:                // Check if we are in a transaction or not. We have no trace on the driver
1710:                // side if a read query has already been executed or not in the current
1711:                // transaction (if any). We let the controller check for this (we only check
1712:                // for writes here) as well as if the underlying databases support the
1713:                // transaction isolation level. If this is not supported, the driver will
1714:                // send back an exception.
1715:                if ((autoCommit == false) && writeExecutedInTransaction)
1716:                    throw new DriverSQLException(
1717:                            getCurrentMethodName()
1718:                                    + " cannot be called in a transaction that has executed write requests.");
1719:
1720:                if (level != isolationLevel) { // Only try to change if there is a new value
1721:                    if ((level == TRANSACTION_READ_COMMITTED)
1722:                            || (level == TRANSACTION_READ_UNCOMMITTED)
1723:                            || (level == TRANSACTION_REPEATABLE_READ)
1724:                            || (level == TRANSACTION_SERIALIZABLE)) {
1725:                        try {
1726:                            sendCommand(Commands.SetTransactionIsolation);
1727:                            socketOutput.writeInt(level);
1728:                            socketOutput.flush();
1729:
1730:                            if (sequoiaUrl.isDebugEnabled())
1731:                                System.out
1732:                                        .println("Setting transaction isolation level to "
1733:                                                + level);
1734:
1735:                            receiveBooleanOrException();
1736:                            // Success
1737:                            isolationLevel = level;
1738:                            return;
1739:
1740:                        } catch (SerializableException e) {
1741:                            throw new DriverSQLException(e);
1742:                        } catch (IOException ioe) {
1743:                            try {
1744:                                // Connection failed, try to reconnect and re-set the transaction
1745:                                // isolation level
1746:                                reconnect();
1747:                                setTransactionIsolation(level);
1748:                            } catch (DriverSQLException e1) {
1749:                                throw new DriverSQLException(
1750:                                        "Connection lost while setting the transaction isolation level '"
1751:                                                + level
1752:                                                + "' and automatic reconnect failed("
1753:                                                + e1 + ")", e1);
1754:                            }
1755:                        }
1756:                    } else
1757:                        throw new DriverSQLException(
1758:                                "Invalid transaction isolation level " + level);
1759:                } // we were already in that level; do nothing.
1760:            }
1761:
1762:            /**
1763:             * Sequoia does NOT support type map.
1764:             * 
1765:             * @param map ignored
1766:             * @exception SQLException not supported
1767:             */
1768:            public void setTypeMap(java.util.Map map) throws SQLException {
1769:                throw new NotImplementedException(getCurrentMethodName());
1770:            }
1771:
1772:            /*
1773:             * Connection Sequoia internals
1774:             */
1775:
1776:            /**
1777:             * Begins a new transaction if needed (<code>mustBeginTransaction</code> is
1778:             * set to <code>true</code>).
1779:             * 
1780:             * @throws DriverSQLException if begin fails
1781:             */
1782:            private void beginTransactionIfNeeded() throws DriverSQLException {
1783:                if (!mustBeginTransaction)
1784:                    return;
1785:
1786:                begin();
1787:                this .mustBeginTransaction = false;
1788:            }
1789:
1790:            /**
1791:             * Fetch multiple results from a query executed with Statement.execute()
1792:             * 
1793:             * @return the list of results
1794:             */
1795:            private List fetchMultipleResultsFromStream(String callerName)
1796:                    throws IOException, SerializableException,
1797:                    ProtocolException {
1798:                boolean hasResult;
1799:                int updateCount = 0;
1800:                LinkedList results = new LinkedList();
1801:                do {
1802:                    hasResult = receiveBooleanOrException();
1803:                    if (hasResult) {
1804:                        DriverResultSet rs = receiveResultSet(callerName);
1805:                        if (rs == null) {
1806:                            // This happens during transparent failover when the controller's
1807:                            // request cache hasn't found a result for a given request.
1808:                            return null;
1809:                        } else {
1810:                            results.addLast(rs);
1811:                        }
1812:                    } else {
1813:                        updateCount = receiveIntOrException();
1814:                        results.addLast(new Integer(updateCount));
1815:                    }
1816:                } while (hasResult || updateCount != -1);
1817:                return results;
1818:            }
1819:
1820:            /**
1821:             * Fetch named parameters from the stream.
1822:             * 
1823:             * @return HashMap of <ParameterName,ParameterValue> or null
1824:             * @throws ProtocolException if a protocol error occured
1825:             * @throws IOException if an error with the socket occured
1826:             * @throws SerializableException if a problem occured deserializing an object
1827:             */
1828:            private HashMap fetchNamedParameters() throws ProtocolException,
1829:                    IOException, SerializableException {
1830:                if (sequoiaUrl.isDebugEnabled())
1831:                    System.out.println("Retrieving named parameters");
1832:                String paramName = receiveStringOrException();
1833:                if ("0".equals(paramName))
1834:                    return null;
1835:                HashMap params = new HashMap();
1836:                while (!"0".equals(paramName)) {
1837:                    Object value = receiveObject();
1838:                    params.put(paramName, value);
1839:                    paramName = receiveStringOrException();
1840:                }
1841:                return params;
1842:            }
1843:
1844:            /**
1845:             * Fetch OUT parameters from the stream.
1846:             * 
1847:             * @return HashMap of <ParameterName,ParameterValue> or null
1848:             * @throws ProtocolException if a protocol error occured
1849:             * @throws IOException if an error with the socket occured
1850:             * @throws SerializableException if a problem occured deserializing an object
1851:             */
1852:            private HashMap fetchOutParameters() throws ProtocolException,
1853:                    IOException, SerializableException {
1854:                if (sequoiaUrl.isDebugEnabled())
1855:                    System.out.println("Retrieving out parameters");
1856:
1857:                int index = receiveIntOrException();
1858:                if (index == 0)
1859:                    return null;
1860:                HashMap params = new HashMap();
1861:                while (index != 0) {
1862:                    Object value = receiveObject();
1863:                    params.put(new Integer(index), value);
1864:                    index = receiveIntOrException();
1865:                }
1866:                return params;
1867:            }
1868:
1869:            /**
1870:             * Set the autocommit mode and read-only status on this request.
1871:             * 
1872:             * @param request The request to set
1873:             */
1874:            private void setConnectionParametersOnRequest(Request request) {
1875:                request.setIsAutoCommit(autoCommit);
1876:            }
1877:
1878:            /**
1879:             * Receive an object from the stream by fetching a tag first and then the
1880:             * value from the proper serializer.
1881:             * 
1882:             * @return the deserialized object (can be null)
1883:             * @throws IOException if a socket error occurs
1884:             * @throws ProtocolException if a protocol corruption is detected
1885:             */
1886:            private Object receiveObject() throws IOException,
1887:                    ProtocolException {
1888:                TypeTag tag = new TypeTag(socketInput);
1889:
1890:                // Handle the null specific case
1891:                if (TypeTag.JAVA_NULL.equals(tag))
1892:                    return null;
1893:
1894:                // We have a real object to de-serialize
1895:                try {
1896:                    Serializer serializer = SQLDataSerialization
1897:                            .getSerializer(tag);
1898:                    return serializer.receiveFromStream(socketInput);
1899:                } catch (IllegalArgumentException iae) {
1900:                    ProtocolException pe = new ProtocolException(
1901:                            "Protocol corruption: received unknown TypeTag "
1902:                                    + tag + " when receiving object.");
1903:                    pe.initCause(iae);
1904:                    throw pe;
1905:                }
1906:            }
1907:
1908:            /**
1909:             * Returns a DriverResultSet read from the stream or throws the
1910:             * SerializableException that came instead
1911:             * 
1912:             * @param callerName used for error messages. Is this really useful?
1913:             * @return received ResultSet
1914:             * @throws IOException stream or protocol error
1915:             * @throws SerializableException received from the controller
1916:             */
1917:            private DriverResultSet receiveResultSet(String callerName)
1918:                    throws IOException, ProtocolException,
1919:                    SerializableException {
1920:                TypeTag tag = new TypeTag(socketInput);
1921:
1922:                if (TypeTag.NULL_RESULTSET.equals(tag))
1923:                    return null;
1924:
1925:                if (TypeTag.RESULTSET.equals(tag)) {
1926:                    DriverResultSet drs = new DriverResultSet(this );
1927:                    return drs;
1928:                }
1929:
1930:                if (TypeTag.EXCEPTION.equals(tag))
1931:                    throw receiveException();
1932:
1933:                throw new ProtocolException(callerName
1934:                        + ": expected a resultset, received unexpected tag: "
1935:                        + tag);
1936:            }
1937:
1938:            /**
1939:             * Deserialize SQL warnings from the stream: converts BackendDriverException
1940:             * to an SQLWarning chain
1941:             * 
1942:             * @return the deserialized warning chain
1943:             * @throws IOException stream error
1944:             * @throws ProtocolException protocol error
1945:             * @throws SerializableException
1946:             */
1947:            private SQLWarning receiveSQLWarnings() throws IOException,
1948:                    ProtocolException, SerializableException {
1949:                if (!receiveBooleanOrException())
1950:                    // no warning
1951:                    return null;
1952:                // Receive the warning as a BackendDriverException
1953:                SerializableException e = receiveException();
1954:                if (!(e instanceof  BackendDriverException))
1955:                    throw new ProtocolException(
1956:                            "Unknown exception received instead of SQLWarning");
1957:                return convertToSQLWarnings(e);
1958:            }
1959:
1960:            /**
1961:             * Deserialize an exception from the stream: converts explicit protocol typing
1962:             * into java types.
1963:             * 
1964:             * @return the deserialized exception read from the stream
1965:             * @throws IOException stream error
1966:             * @throws ProtocolException protocol error
1967:             */
1968:            private SerializableException receiveException()
1969:                    throws IOException, ProtocolException {
1970:                TypeTag exceptionType = new TypeTag(socketInput);
1971:
1972:                if (TypeTag.BACKEND_EXCEPTION.equals(exceptionType))
1973:                    return new BackendDriverException(socketInput);
1974:                if (TypeTag.CORE_EXCEPTION.equals(exceptionType))
1975:                    return new ControllerCoreException(socketInput);
1976:
1977:                throw new ProtocolException("received unknown exception type");
1978:            }
1979:
1980:            /**
1981:             * Returns a String read from the stream or throws the SerializableException
1982:             * that came instead.
1983:             * 
1984:             * @throws IOException stream or protocol error
1985:             * @throws SerializableException coming from the controller
1986:             * @throws ProtocolException protocol error
1987:             */
1988:            private String receiveStringOrException() throws IOException,
1989:                    SerializableException, ProtocolException {
1990:                TypeTag tag = new TypeTag(socketInput);
1991:                if (TypeTag.NOT_EXCEPTION.equals(tag)) {
1992:                    String answer = socketInput.readLongUTF();
1993:                    return answer;
1994:                }
1995:
1996:                throw receiveException();
1997:            }
1998:
1999:            /**
2000:             * Returns a boolean read from the stream or throws the SerializableException
2001:             * that came instead.
2002:             * 
2003:             * @throws IOException stream or protocol error
2004:             * @throws SerializableException coming from the controller
2005:             * @throws ProtocolException protocol error
2006:             */
2007:            private boolean receiveBooleanOrException() throws IOException,
2008:                    SerializableException, ProtocolException {
2009:                TypeTag tag = new TypeTag(socketInput);
2010:                if (TypeTag.NOT_EXCEPTION.equals(tag)) {
2011:                    boolean answer = socketInput.readBoolean();
2012:                    return answer;
2013:                }
2014:
2015:                throw receiveException();
2016:            }
2017:
2018:            /**
2019:             * Returns a int read from the stream or throws the SerializableException that
2020:             * came instead.
2021:             * 
2022:             * @throws IOException stream or protocol error
2023:             * @throws SerializableException coming from the controller
2024:             * @throws ProtocolException protocol error
2025:             */
2026:            private int receiveIntOrException() throws IOException,
2027:                    SerializableException, ProtocolException {
2028:                TypeTag tag = new TypeTag(socketInput);
2029:                if (TypeTag.NOT_EXCEPTION.equals(tag)) {
2030:                    int answer = socketInput.readInt();
2031:                    return answer;
2032:                }
2033:
2034:                throw receiveException();
2035:            }
2036:
2037:            /**
2038:             * Returns a long read from the stream or throws the SerializableException
2039:             * that came instead.
2040:             * 
2041:             * @throws IOException stream or protocol error
2042:             * @throws SerializableException coming from the controller
2043:             * @throws ProtocolException protocol error
2044:             */
2045:            private long receiveLongOrException() throws IOException,
2046:                    SerializableException, ProtocolException {
2047:                TypeTag tag = new TypeTag(socketInput);
2048:                if (TypeTag.NOT_EXCEPTION.equals(tag)) {
2049:                    long answer = socketInput.readLong();
2050:                    return answer;
2051:                }
2052:
2053:                throw receiveException();
2054:            }
2055:
2056:            /**
2057:             * Serialize a savepoint on the output stream by sending only the needed
2058:             * parameters to reconstruct it on the controller
2059:             * 
2060:             * @param savepoint the savepoint to send
2061:             * @throws IOException if fails
2062:             */
2063:            private void savepointOnStream(Savepoint savepoint)
2064:                    throws IOException {
2065:                writeExecutedInTransaction = true;
2066:
2067:                try {
2068:                    socketOutput.writeLongUTF(savepoint.getSavepointName());
2069:                    return;
2070:                } catch (SQLException ignore) {
2071:                    // Ignoring because we are dealing with an un-named savepoint
2072:                }
2073:
2074:                try {
2075:                    socketOutput.writeLongUTF(String.valueOf(savepoint
2076:                            .getSavepointId()));
2077:                    return;
2078:                } catch (SQLException ignore) {
2079:                    // We should never get here
2080:                }
2081:            }
2082:
2083:            /**
2084:             * Check if the given release savepoint has been successfully performed.
2085:             * 
2086:             * @return true if the release savepoint has been successfully performed
2087:             * @throws DriverSQLException if an error occured
2088:             */
2089:            private boolean retrieveReleaseSavepoint(Savepoint savepoint)
2090:                    throws DriverSQLException {
2091:                try {
2092:                    sendCommand(Commands.RetrieveReleaseSavepoint);
2093:                    socketOutput.writeLongUTF(savepoint.getSavepointName());
2094:                    socketOutput.flush();
2095:                    return receiveBooleanOrException();
2096:                } catch (Throwable e) {
2097:                    throw new DriverSQLException(getCurrentMethodName()
2098:                            + " failed on new controller (" + e + ")");
2099:                }
2100:            }
2101:
2102:            /**
2103:             * Check if the given commit has been successfully performed.
2104:             * 
2105:             * @return the transaction id if the commit has been successfully performed
2106:             * @throws DriverSQLException if an error occured on the commit
2107:             */
2108:            private long retrieveCommitResult() throws DriverSQLException {
2109:                try {
2110:                    sendCommand(Commands.RetrieveCommitResult);
2111:                    socketOutput.flush();
2112:                    return receiveLongOrException();
2113:                } catch (Throwable e) {
2114:                    throw new DriverSQLException(getCurrentMethodName()
2115:                            + " failed on new controller (" + e + ")");
2116:                }
2117:            }
2118:
2119:            /**
2120:             * Check if the given rollback has been successfully performed.
2121:             * 
2122:             * @return the transaction id if the rollback has been successfully performed
2123:             * @throws DriverSQLException if an error occured on the rollback
2124:             */
2125:            private long retrieveRollbackResult() throws DriverSQLException {
2126:                try {
2127:                    sendCommand(Commands.RetrieveRollbackResult);
2128:                    socketOutput.flush();
2129:                    return receiveLongOrException();
2130:                } catch (Throwable e) {
2131:                    throw new DriverSQLException(getCurrentMethodName()
2132:                            + " failed on new controller (" + e + ")");
2133:                }
2134:            }
2135:
2136:            /**
2137:             * Check if the given query already executed or not on the controller we are
2138:             * currently connected to.
2139:             * 
2140:             * @param request the stored procedure to check
2141:             * @return null if not found or a List composed of a
2142:             *         <code>java.sql.ResultSet</code> value, an <code>ArrayList</code>
2143:             *         of OUT parameters, and a <code>HashMap</code> of named parameters
2144:             *         result objects.
2145:             * @throws DriverSQLException if an error occurs
2146:             */
2147:            private ResultAndWarnings retrieveExecuteQueryResultWithParameters(
2148:                    Request request) throws DriverSQLException {
2149:                try {
2150:                    sendCommand(Commands.RetrieveExecuteQueryResultWithParameters);
2151:                    socketOutput.writeLong(request.getId());
2152:                    socketOutput.flush();
2153:                    SQLWarning sqlw = receiveSQLWarnings();
2154:                    DriverResultSet drs = receiveResultSet(getCurrentMethodName());
2155:                    if (drs == null)
2156:                        return null;
2157:                    List result = new ArrayList(3);
2158:                    result.add(drs);
2159:                    result.add(fetchOutParameters());
2160:                    result.add(fetchNamedParameters());
2161:                    return new ResultAndWarnings(result, sqlw);
2162:                } catch (Throwable e) {
2163:                    throw new DriverSQLException(getCurrentMethodName()
2164:                            + " failed on new controller (" + e + ")");
2165:                }
2166:            }
2167:
2168:            /**
2169:             * Check if the given query already executed or not on the controller we are
2170:             * currently connected to.
2171:             * 
2172:             * @param request the request to check
2173:             * @return -1 if not found or a List composed of an <code>Integer</code>
2174:             *         (number of updated rows), an <code>ArrayList</code> of OUT
2175:             *         parameters, and a <code>HashMap</code> of named parameters result
2176:             *         objects.
2177:             * @throws DriverSQLException if an error occurs
2178:             */
2179:            private ResultAndWarnings retrieveExecuteUpdateResultWithParameters(
2180:                    Request request) throws DriverSQLException {
2181:                try {
2182:                    sendCommand(Commands.RetrieveExecuteUpdateResultWithParameters);
2183:                    socketOutput.writeLong(request.getId());
2184:                    socketOutput.flush();
2185:                    SQLWarning sqlw = receiveSQLWarnings();
2186:                    int updateCount = receiveIntOrException();
2187:                    if (updateCount == -1)
2188:                        return null; // No result found in failover
2189:                    List result = new ArrayList(3);
2190:                    result.add(new Integer(updateCount));
2191:                    result.add(fetchOutParameters());
2192:                    result.add(fetchNamedParameters());
2193:                    return new ResultAndWarnings(result, sqlw);
2194:                } catch (Throwable e) {
2195:                    throw new DriverSQLException(getCurrentMethodName()
2196:                            + " failed on new controller (" + e + ")");
2197:                }
2198:            }
2199:
2200:            /**
2201:             * Check if the given query already executed or not on the controller we are
2202:             * currently connected to.
2203:             * 
2204:             * @param request the request to check
2205:             * @return null if not found or a List composed of 1. a <code>List</code> of
2206:             *         results <code>java.sql.ResultSet</code> value, 2. an
2207:             *         <code>ArrayList</code> of OUT parameters, and 3. a
2208:             *         <code>HashMap</code> of named parameters result objects.
2209:             * @throws DriverSQLException if an error occurs
2210:             */
2211:            private ResultAndWarnings retrieveExecuteResultWithParameters(
2212:                    Request request) throws DriverSQLException {
2213:                try {
2214:                    sendCommand(Commands.RetrieveExecuteResultWithParameters);
2215:                    socketOutput.writeLong(request.getId());
2216:                    socketOutput.flush();
2217:                    SQLWarning statementWarnings = receiveSQLWarnings();
2218:                    List results = fetchMultipleResultsFromStream(getCurrentMethodName());
2219:                    if (results == null)
2220:                        return null; // No result found in failover
2221:                    List result = new ArrayList(3);
2222:                    result.add(results);
2223:                    result.add(fetchOutParameters());
2224:                    result.add(fetchNamedParameters());
2225:                    return new ResultAndWarnings(result, statementWarnings);
2226:                } catch (Throwable e) {
2227:                    throw new DriverSQLException(getCurrentMethodName()
2228:                            + " failed on new controller (" + e + ")");
2229:                }
2230:            }
2231:
2232:            /**
2233:             * Check if the given query already executed or not on the controller we are
2234:             * currently connected to.
2235:             * 
2236:             * @param request the request to check
2237:             * @return int the number of updated rows or -1 if not found
2238:             * @throws DriverSQLException if an error occurs
2239:             */
2240:            private ResultAndWarnings retrieveExecuteUpdateResult(
2241:                    Request request) throws DriverSQLException {
2242:                try {
2243:                    sendCommand(Commands.RetrieveExecuteUpdateResult);
2244:                    socketOutput.writeLong(request.getId());
2245:                    socketOutput.flush();
2246:                    SQLWarning sqlw = receiveSQLWarnings();
2247:                    int uc = receiveIntOrException();
2248:                    return new ResultAndWarnings(uc, sqlw);
2249:                } catch (Throwable e) {
2250:                    throw new DriverSQLException(getCurrentMethodName()
2251:                            + " failed on new controller (" + e + ")");
2252:                }
2253:            }
2254:
2255:            /**
2256:             * Check if the given query already executed or not on the controller we are
2257:             * currently connected to.
2258:             * 
2259:             * @param request the request to check
2260:             * @return int the number of updated rows or -1 if not found
2261:             * @throws DriverSQLException if an error occurs
2262:             */
2263:            private DriverGeneratedKeysResult retrieveExecuteUpdateWithKeysResult(
2264:                    Request request) throws DriverSQLException {
2265:                try {
2266:                    sendCommand(Commands.RetrieveExecuteUpdateWithKeysResult);
2267:                    socketOutput.writeLong(request.getId());
2268:                    socketOutput.flush();
2269:
2270:                    SQLWarning sqlw = receiveSQLWarnings();
2271:                    int updateCount = receiveIntOrException();
2272:                    if (updateCount == -1)
2273:                        return null;
2274:
2275:                    // Fetch the ResultSet containing the autogenerated keys.
2276:                    TypeTag tag = new TypeTag(socketInput);
2277:                    if (TypeTag.RESULTSET.equals(tag)) {
2278:                        DriverResultSet drs = new DriverResultSet(this );
2279:                        return new DriverGeneratedKeysResult(drs, updateCount,
2280:                                sqlw);
2281:                    }
2282:
2283:                    if (TypeTag.NULL_RESULTSET.equals(tag))
2284:                        return new DriverGeneratedKeysResult(null, updateCount,
2285:                                sqlw);
2286:
2287:                    // Error, unexpected answer
2288:                    throw new ProtocolException(getCurrentMethodName()
2289:                            + ": protocol corruption for request "
2290:                            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH));
2291:                } catch (Throwable e) {
2292:                    throw new DriverSQLException(getCurrentMethodName()
2293:                            + " failed on new controller (" + e + ")");
2294:                }
2295:            }
2296:
2297:            /**
2298:             * Check if the given query already executed or not on the controller we are
2299:             * currently connected to.
2300:             * 
2301:             * @param request the request to check
2302:             * @return a <code>List</code> of results or null if not found
2303:             * @throws DriverSQLException if an error occurs
2304:             */
2305:            private ResultAndWarnings retrieveExecuteResult(Request request)
2306:                    throws DriverSQLException {
2307:                try {
2308:                    sendCommand(Commands.RetrieveExecuteResult);
2309:                    socketOutput.writeLong(request.getId());
2310:                    socketOutput.flush();
2311:                    SQLWarning statementWarnings = receiveSQLWarnings();
2312:                    List resList = fetchMultipleResultsFromStream(getCurrentMethodName());
2313:                    return new ResultAndWarnings(resList, statementWarnings);
2314:                } catch (Throwable e) {
2315:                    throw new DriverSQLException(getCurrentMethodName()
2316:                            + " failed on new controller (" + e + ")");
2317:                }
2318:            }
2319:
2320:            void reallyClose() throws IOException, DriverSQLException {
2321:                sendCommand(Commands.Close);
2322:            }
2323:
2324:            /**
2325:             * Try to reconnect to the next controller chosen according to the
2326:             * policy specified in the JDBC URL of this connection.
2327:             * 
2328:             * @throws DriverSQLException if an error occured during reconnect
2329:             */
2330:            private synchronized void reconnect() throws DriverSQLException,
2331:                    VirtualDatabaseUnavailableException {
2332:                // Get rid of current connection
2333:                try {
2334:                    this .socket.close();
2335:                } catch (IOException ignore) {
2336:                }
2337:                try {
2338:                    this .socketInput.close();
2339:                } catch (IOException ignore) {
2340:                }
2341:                try {
2342:                    this .socketOutput.close();
2343:                } catch (IOException ignore) {
2344:                }
2345:                // only one (Connection) accessing the pool at a time
2346:                synchronized (driver.pendingConnectionClosing) {
2347:                    if (driver.pendingConnectionClosing.remove(this ))
2348:                        System.out
2349:                                .println("Warning! Closed call before reconnect");
2350:                }
2351:
2352:                SequoiaUrl tempUrl = sequoiaUrl;
2353:                if (persistentConnection) {
2354:                    /**
2355:                     * We do not want to create a persistent connection on the new connection,
2356:                     * because we will just close it during the restore operation. We need to
2357:                     * make a copy of sequoiaUrl, because it is shared with other connections.
2358:                     */
2359:                    try {
2360:                        tempUrl = sequoiaUrl.getTemporaryCloneForReconnection(
2361:                                vdbUser, vdbPassword);
2362:                    } catch (SQLException e) {
2363:                        // if we could not get a new sequoiaUrl we will just use the original
2364:                    }
2365:                }
2366:
2367:                Connection newconn = null;
2368:                // At this point, the current controller is down and we have to try a
2369:                // new one that will be allocated by the policy specified in the URL.
2370:                try {
2371:                    newconn = driver.getConnectionToNewController(tempUrl);
2372:                    if (newconn != null)
2373:                        controllerInfo = newconn.getControllerInfo();
2374:                } catch (AuthenticationException e) {
2375:                    // Should not happen, this probably mean an inconsistency in controller
2376:                    // configuration but safely ignore (see below)
2377:                    String msg = "Warning! Authentication exception received on connection retry, controller configuration might be inconsistent";
2378:                    if (sequoiaUrl.isInfoEnabled())
2379:                        System.out.println(msg);
2380:                    throw new DriverSQLException(msg, e);
2381:                } catch (NoMoreControllerException nmc) {
2382:                    throw new DriverSQLException(nmc);
2383:                } catch (GeneralSecurityException gse) {
2384:                    String msg = "Fatal General Security Exception received while trying to reconnect";
2385:                    if (sequoiaUrl.isInfoEnabled())
2386:                        System.out.println(msg);
2387:                    throw new DriverSQLException(msg, gse);
2388:                }
2389:
2390:                // newconn cannot be null here else an excepection would have been thrown
2391:                // earlier.
2392:
2393:                // Success: let's use the new connection for ourselves
2394:                this .socket = newconn.socket;
2395:                this .socketInput = newconn.socketInput;
2396:                this .socketOutput = newconn.socketOutput;
2397:                this .controllerInfo = newconn.controllerInfo;
2398:                this .isClosed = false;
2399:                try {
2400:                    if (sequoiaUrl.isDebugEnabled())
2401:                        System.out
2402:                                .println("Restoring connection state on controller "
2403:                                        + controllerInfo);
2404:                    sendCommand(Commands.RestoreConnectionState);
2405:                    socketOutput.writeBoolean(writeExecutedInTransaction);
2406:                    if (mustBeginTransaction) { // Say that we are in autoCommit, begin will be done later
2407:                        // Fixes SEQUOIA-522
2408:                        socketOutput.writeBoolean(true);
2409:                    } else {
2410:                        socketOutput.writeBoolean(autoCommit);
2411:                        if (!autoCommit)
2412:                            socketOutput.writeLong(transactionId);
2413:                    }
2414:                    socketOutput.writeBoolean(persistentConnection);
2415:                    if (persistentConnection)
2416:                        socketOutput.writeLong(persistentConnectionId);
2417:                    socketOutput.writeBoolean(retrieveSQLWarnings);
2418:                    socketOutput.flush();
2419:                    // Read ack. We won't do anything with it but reading this it is the only
2420:                    // way to dectect that the controller is down (see SEQUOIA-632)
2421:                    socketInput.readBoolean();
2422:
2423:                    // Restore read-only state (not part of RestoreConnectionState command for
2424:                    // backward compatibility)
2425:                    setReadOnly(readOnly);
2426:                } catch (IOException e) {
2427:                    reconnect();
2428:                }
2429:            }
2430:
2431:            /**
2432:             * Before sending a command code, checks that the controller is
2433:             * synchronized/ready to accept it. Then sends it.
2434:             * 
2435:             * @param command to send
2436:             * @throws IOException on socket error
2437:             * @throws DriverSQLException on protocol corruption
2438:             */
2439:            private void sendCommand(int command) throws IOException,
2440:                    DriverSQLException {
2441:                if (socketInput.readInt() != Commands.ControllerPrompt)
2442:                    throw new DriverSQLException(
2443:                            "Protocol corruption while trying to send command: "
2444:                                    + command + ". Check the previous command");
2445:                socketOutput.writeInt(Commands.CommandPrefix);
2446:                socketOutput.writeInt(command);
2447:            }
2448:
2449:            /**
2450:             * @see #close()
2451:             */
2452:            private void throwSQLExceptionIfClosed(String message)
2453:                    throws DriverSQLException {
2454:                if (isClosed)
2455:                    throw new DriverSQLException(message);
2456:            }
2457:
2458:            /**
2459:             * @see #close()
2460:             */
2461:            private void throwSQLExceptionIfClosed() throws DriverSQLException {
2462:                // default message
2463:                throwSQLExceptionIfClosed("Tried to operate on a closed Connection");
2464:            }
2465:
2466:            private DriverSQLException wrapIOExceptionInDriverSQLException(
2467:                    String callerName, IOException ioe) {
2468:                return new DriverSQLException("I/O Error on method "
2469:                        + callerName + "():\n" + ioe.getLocalizedMessage(), ioe);
2470:            }
2471:
2472:            /**
2473:             * Utility function to convert the given chain of backendException to a chain
2474:             * of SQLWarnings
2475:             * 
2476:             * @param toConvert exception chain to convert
2477:             */
2478:            protected SQLWarning convertToSQLWarnings(
2479:                    SerializableException toConvert) {
2480:                if (toConvert == null)
2481:                    return null;
2482:                SQLWarning sqlw = new SQLWarning(toConvert.getMessage(),
2483:                        toConvert.getSQLState(), toConvert.getErrorCode());
2484:                Throwable t = toConvert.getCause();
2485:                if (t != null) {
2486:                    if (t instanceof  SerializableException)
2487:                        sqlw
2488:                                .setNextWarning(convertToSQLWarnings((SerializableException) t));
2489:                    else if (sequoiaUrl.isDebugEnabled())
2490:                        System.out.println("Unexpected exception type "
2491:                                + t.getClass()
2492:                                + "while converting warning chain");
2493:                }
2494:                return sqlw;
2495:            }
2496:
2497:            /**
2498:             * Performs a read request and return the reply.
2499:             * 
2500:             * @param request the read request to execute
2501:             * @return a <code>java.sql.ResultSet</code> value
2502:             * @exception DriverSQLException if an error occurs
2503:             */
2504:            protected synchronized DriverResultSet statementExecuteQuery(
2505:                    RequestWithResultSetParameters request)
2506:                    throws DriverSQLException, NotImplementedException {
2507:                throwSQLExceptionIfClosed("Closed connection cannot process request '"
2508:                        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2509:                beginTransactionIfNeeded();
2510:
2511:                try {
2512:                    setConnectionParametersOnRequest(request);
2513:                    sendCommand(Commands.StatementExecuteQuery);
2514:                    request.sendToStream(socketOutput);
2515:                    socketOutput.flush();
2516:                    if (sequoiaUrl.isDebugEnabled())
2517:                        System.out.println("Executing "
2518:                                + getCurrentMethodName() + " with request "
2519:                                + request);
2520:
2521:                    SQLWarning statementWarnings = receiveSQLWarnings();
2522:                    TypeTag tag = new TypeTag(socketInput);
2523:
2524:                    // First case, we received our ResultSet, let's fetch it.
2525:                    if (TypeTag.RESULTSET.equals(tag)) {
2526:                        try {
2527:                            DriverResultSet drs = new DriverResultSet(this );
2528:                            drs.setStatementWarnings(statementWarnings);
2529:                            return drs;
2530:                        } catch (ProtocolException e) {
2531:                            throw new DriverSQLException(
2532:                                    "Protocol corruption in "
2533:                                            + getCurrentMethodName()
2534:                                            + " with request "
2535:                                            + request
2536:                                                    .getSqlShortForm(ABBREV_REQUEST_LENGTH),
2537:                                    e);
2538:                        } catch (IOException e) { // Error while reading, retry
2539:                            if (sequoiaUrl.isInfoEnabled())
2540:                                System.out
2541:                                        .println("IOException occured trying to reconnect ("
2542:                                                + e.getLocalizedMessage() + ")");
2543:                            reconnect();
2544:                            return statementExecuteQuery(request);
2545:                        }
2546:                    }
2547:
2548:                    if (TypeTag.NULL_RESULTSET.equals(tag))
2549:                        return null;
2550:
2551:                    // From this point on, we had an exception
2552:                    if (TypeTag.EXCEPTION.equals(tag)) {
2553:                        Exception recvEx = null;
2554:                        recvEx = receiveException();
2555:                        // dirty hack until cleanup
2556:                        if (recvEx instanceof  ControllerCoreException)
2557:                            recvEx = ((ControllerCoreException) recvEx)
2558:                                    .compatibilityWrapperHack();
2559:
2560:                        if (recvEx instanceof  NoMoreBackendException) {
2561:                            if (sequoiaUrl.isInfoEnabled())
2562:                                System.out
2563:                                        .println("No more backend available on controller");
2564:                            throw new DriverSQLException(recvEx);
2565:                        } else if (recvEx instanceof  IOException) {
2566:                            // We shouldn't have been able to receive this IOE because it means
2567:                            // that the socket died (at the controller side)
2568:                            throw new ProtocolException(
2569:                                    "Received exception of unexpected type ("
2570:                                            + ((IOException) recvEx)
2571:                                                    .getLocalizedMessage()
2572:                                            + ")");
2573:                        } else if (recvEx instanceof  BackendDriverException) {
2574:                            // TODO: temporary fix until DriverSQLException is fixed
2575:                            throw new DriverSQLException(
2576:                                    (SerializableException) recvEx);
2577:                        } else if (recvEx instanceof  NotImplementedException) {
2578:                            // incredibly ugly.
2579:                            throw (NotImplementedException) recvEx;
2580:                        } else if (recvEx instanceof  SQLException) {
2581:                            throw new DriverSQLException((SQLException) recvEx);
2582:                        }
2583:                    }
2584:
2585:                    // Error, unexpected answer
2586:                    throw new ProtocolException("Protocol corruption in "
2587:                            + getCurrentMethodName() + " for request "
2588:                            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH));
2589:                } catch (SerializableException se) {
2590:                    throw new DriverSQLException(se);
2591:                } catch (RuntimeException e) {
2592:                    e.printStackTrace();
2593:                    throw new DriverSQLException(getCurrentMethodName()
2594:                            + ": error occured while request '"
2595:                            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
2596:                            + "' was processed by Sequoia Controller", e);
2597:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
2598:                    try {
2599:                        if (sequoiaUrl.isInfoEnabled())
2600:                            System.out
2601:                                    .println("IOException occured trying to reconnect ("
2602:                                            + e.getMessage() + ")");
2603:                        reconnect();
2604:                        return statementExecuteQuery(request);
2605:                    } catch (DriverSQLException e1) {
2606:                        throw new DriverSQLException(
2607:                                "Connection lost while executing "
2608:                                        + getCurrentMethodName()
2609:                                        + " with request '"
2610:                                        + request
2611:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
2612:                                        + "' and automatic reconnect failed ("
2613:                                        + e1 + ")", e1);
2614:                    }
2615:                }
2616:            }
2617:
2618:            /**
2619:             * Performs a write request and return the number of rows affected.
2620:             * 
2621:             * @param request the write request to execute
2622:             * @return number of rows affected
2623:             * @exception DriverSQLException if an error occurs
2624:             */
2625:            protected synchronized ResultAndWarnings statementExecuteUpdate(
2626:                    Request request) throws DriverSQLException {
2627:                throwSQLExceptionIfClosed("Closed connection cannot process request '"
2628:                        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2629:                beginTransactionIfNeeded();
2630:
2631:                boolean requestIdIsSet = false;
2632:                try {
2633:                    setConnectionParametersOnRequest(request);
2634:                    sendCommand(Commands.StatementExecuteUpdate);
2635:                    request.sendToStream(socketOutput);
2636:                    socketOutput.flush();
2637:                    if (sequoiaUrl.isDebugEnabled())
2638:                        System.out.println("Executing "
2639:                                + getCurrentMethodName() + " with request "
2640:                                + request);
2641:
2642:                    request.setId(receiveLongOrException());
2643:                    requestIdIsSet = true;
2644:                    if (!autoCommit)
2645:                        writeExecutedInTransaction = true;
2646:
2647:                    SQLWarning statementWarnings = receiveSQLWarnings();
2648:                    int uc = receiveIntOrException();
2649:                    return new ResultAndWarnings(uc, statementWarnings);
2650:
2651:                } catch (SerializableException se) {
2652:                    throw new DriverSQLException(se);
2653:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
2654:                    try {
2655:                        reconnect();
2656:                        if (requestIdIsSet) { // Controller handled the query, check if it was executed
2657:                            ResultAndWarnings result = retrieveExecuteUpdateResult(request);
2658:                            if (result != null && result.getUpdateCount() != -1) {
2659:                                return result;
2660:                            }
2661:                        }
2662:                        // At this point the query failed before any controller succeeded in
2663:                        // executing the query
2664:
2665:                        return statementExecuteUpdate(request);
2666:                    } catch (DriverSQLException e1) {
2667:                        throw new DriverSQLException(
2668:                                "Connection lost while executing "
2669:                                        + getCurrentMethodName()
2670:                                        + " with request '"
2671:                                        + request
2672:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
2673:                                        + "' and automatic reconnect failed ("
2674:                                        + e1 + ")", e1);
2675:                    }
2676:                }
2677:            }
2678:
2679:            /**
2680:             * Call a request that returns a list of results.
2681:             * 
2682:             * @param request the request to execute
2683:             * @return a <code>List</code> of results
2684:             * @throws DriverSQLException if an error occurs
2685:             */
2686:            protected synchronized ResultAndWarnings statementExecute(
2687:                    RequestWithResultSetParameters request)
2688:                    throws DriverSQLException {
2689:                throwSQLExceptionIfClosed("Closed Connection cannot process request '"
2690:                        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2691:                beginTransactionIfNeeded();
2692:
2693:                boolean requestIdIsSet = false;
2694:                try {
2695:                    setConnectionParametersOnRequest(request);
2696:                    sendCommand(Commands.StatementExecute);
2697:                    request.sendToStream(socketOutput);
2698:                    socketOutput.flush();
2699:                    if (sequoiaUrl.isDebugEnabled())
2700:                        System.out.println("Executing "
2701:                                + getCurrentMethodName() + " with request"
2702:                                + request);
2703:
2704:                    request.setId(receiveLongOrException());
2705:                    requestIdIsSet = true;
2706:                    if (!autoCommit)
2707:                        writeExecutedInTransaction = true;
2708:
2709:                    SQLWarning sqlw = receiveSQLWarnings();
2710:                    List res = fetchMultipleResultsFromStream(getCurrentMethodName());
2711:                    return new ResultAndWarnings(res, sqlw);
2712:                } catch (RuntimeException e) {
2713:                    throw new DriverSQLException(getCurrentMethodName()
2714:                            + ": Error occured while request '"
2715:                            + request.getSqlShortForm(ABBREV_REQUEST_LENGTH)
2716:                            + "' was processed by Sequoia Controller", e);
2717:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
2718:                    try {
2719:                        reconnect();
2720:                        if (requestIdIsSet) { // Controller handled the query, check if it was executed
2721:                            ResultAndWarnings rww = retrieveExecuteResult(request);
2722:                            if (rww != null && rww.getResultList() != null)
2723:                                return rww;
2724:                        }
2725:                        // At this point the query failed before any controller succeeded in
2726:                        // executing the query
2727:
2728:                        return statementExecute(request);
2729:                    } catch (DriverSQLException e1) {
2730:                        throw new DriverSQLException(
2731:                                "Connection lost while executing "
2732:                                        + getCurrentMethodName()
2733:                                        + " with request '"
2734:                                        + request
2735:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
2736:                                        + "' and automatic reconnect failed ("
2737:                                        + e1 + ")", e1);
2738:                    }
2739:                } catch (SerializableException e) {
2740:                    throw new DriverSQLException(e);
2741:                }
2742:            }
2743:
2744:            /**
2745:             * Performs a write request and returns the auto-generated keys
2746:             * 
2747:             * @param request the write request to execute
2748:             * @return auto generated keys
2749:             * @exception DriverSQLException if an error occurs
2750:             */
2751:            protected synchronized DriverGeneratedKeysResult statementExecuteUpdateWithKeys(
2752:                    Request request) throws DriverSQLException {
2753:                throwSQLExceptionIfClosed("Closed Connection cannot process request '"
2754:                        + request.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2755:                beginTransactionIfNeeded();
2756:
2757:                boolean requestIdIsSet = false;
2758:                try {
2759:                    setConnectionParametersOnRequest(request);
2760:                    sendCommand(Commands.StatementExecuteUpdateWithKeys);
2761:                    request.sendToStream(socketOutput);
2762:                    socketOutput.flush();
2763:                    if (sequoiaUrl.isDebugEnabled())
2764:                        System.out.println("Executing "
2765:                                + getCurrentMethodName() + " with request: "
2766:                                + request);
2767:
2768:                    try {
2769:                        request.setId(receiveLongOrException());
2770:                        requestIdIsSet = true;
2771:                        if (!autoCommit)
2772:                            writeExecutedInTransaction = true;
2773:
2774:                        // Receive the warnings
2775:                        SQLWarning sqlw = receiveSQLWarnings();
2776:
2777:                        // Receive the update count or an exception
2778:                        int updateCount = receiveIntOrException();
2779:
2780:                        // Fetch the ResultSet containing the autogenerated keys.
2781:                        TypeTag tag = new TypeTag(socketInput);
2782:                        if (TypeTag.RESULTSET.equals(tag)) {
2783:                            try {
2784:                                DriverResultSet drs = new DriverResultSet(this );
2785:                                return new DriverGeneratedKeysResult(drs,
2786:                                        updateCount, sqlw);
2787:                            } catch (ProtocolException e) {
2788:                                throw new DriverSQLException(
2789:                                        "Protocol corruption in "
2790:                                                + getCurrentMethodName()
2791:                                                + " with request "
2792:                                                + request
2793:                                                        .getSqlShortForm(ABBREV_REQUEST_LENGTH),
2794:                                        e);
2795:                            } catch (IOException e) { // Error while reading, retry
2796:                                if (sequoiaUrl.isInfoEnabled())
2797:                                    System.out
2798:                                            .println("IOException occured trying to reconnect ("
2799:                                                    + e.getLocalizedMessage()
2800:                                                    + ")");
2801:                                reconnect();
2802:                                return statementExecuteUpdateWithKeys(request);
2803:                            }
2804:                        }
2805:
2806:                        if (TypeTag.NULL_RESULTSET.equals(tag))
2807:                            return new DriverGeneratedKeysResult(null,
2808:                                    updateCount, sqlw);
2809:
2810:                        // Error, unexpected answer
2811:                        throw new ProtocolException("Protocol corruption in "
2812:                                + getCurrentMethodName()
2813:                                + " for request "
2814:                                + request
2815:                                        .getSqlShortForm(ABBREV_REQUEST_LENGTH));
2816:                    } catch (SerializableException e) {
2817:                        throw new DriverSQLException(e);
2818:                    }
2819:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
2820:                    try {
2821:                        reconnect();
2822:                        if (requestIdIsSet) { // Controller handled the query, check if it was executed
2823:                            DriverGeneratedKeysResult result = retrieveExecuteUpdateWithKeysResult(request);
2824:                            if (result != null)
2825:                                return result;
2826:                        }
2827:                        // At this point the query failed before any controller succeeded in
2828:                        // executing the query
2829:                        return statementExecuteUpdateWithKeys(request);
2830:                    } catch (DriverSQLException e1) {
2831:                        throw new DriverSQLException(
2832:                                "Connection lost while executing "
2833:                                        + getCurrentMethodName()
2834:                                        + " with request '"
2835:                                        + request
2836:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
2837:                                        + "' and automatic reconnect failed ("
2838:                                        + e1 + ")", e1);
2839:                    }
2840:                }
2841:            }
2842:
2843:            /**
2844:             * Call a stored procedure (with IN/OUT and/or named parameters) that returns
2845:             * a ResultSet.
2846:             * 
2847:             * @param proc the stored procedure call
2848:             * @return a List composed of a <code>java.sql.ResultSet</code> value, an
2849:             *         <code>ArrayList</code> of OUT parameters, and a
2850:             *         <code>HashMap</code> of named parameters result objects.
2851:             * @exception DriverSQLException if an error occurs
2852:             */
2853:            protected synchronized ResultAndWarnings callableStatementExecuteQuery(
2854:                    RequestWithResultSetParameters proc)
2855:                    throws DriverSQLException {
2856:                throwSQLExceptionIfClosed("Closed Connection cannot process request '"
2857:                        + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2858:                beginTransactionIfNeeded();
2859:
2860:                boolean procIdIsSet = false;
2861:                try {
2862:                    setConnectionParametersOnRequest(proc);
2863:                    sendCommand(Commands.CallableStatementExecuteQueryWithParameters);
2864:                    proc.sendToStream(socketOutput);
2865:                    socketOutput.flush();
2866:                    if (sequoiaUrl.isDebugEnabled())
2867:                        System.out.println("Executing "
2868:                                + getCurrentMethodName() + " with procedure '"
2869:                                + proc + "'");
2870:
2871:                    proc.setId(receiveLongOrException());
2872:                    procIdIsSet = true;
2873:                    if (!autoCommit)
2874:                        writeExecutedInTransaction = true;
2875:
2876:                    if (sequoiaUrl.isDebugEnabled())
2877:                        System.out.println("Received unique id " + proc.getId()
2878:                                + " for procedure '" + proc + "'");
2879:
2880:                    SQLWarning sqlw = receiveSQLWarnings();
2881:
2882:                    Exception recvEx = null;
2883:                    TypeTag tag = new TypeTag(socketInput);
2884:
2885:                    DriverResultSet drs = null;
2886:
2887:                    /*
2888:                     * TODO: the code below is a complete mess. One reason is it's still half
2889:                     * legacy design from old protocol, half from the new procotol. It could
2890:                     * easily be made much simpler. We should use #receiveResultSet() TODO:
2891:                     * test NoMoreBackendException
2892:                     */
2893:                    if (!TypeTag.NULL_RESULTSET.equals(tag)) {
2894:                        if (TypeTag.EXCEPTION.equals(tag)) {
2895:                            recvEx = receiveException();
2896:                            // dirty hack until cleanup
2897:                            if (recvEx instanceof  ControllerCoreException)
2898:                                recvEx = ((ControllerCoreException) recvEx)
2899:                                        .compatibilityWrapperHack();
2900:
2901:                            if (recvEx instanceof  DriverSQLException)
2902:                                throw (DriverSQLException) recvEx;
2903:
2904:                            throw new DriverSQLException(recvEx);
2905:                        } else if (!TypeTag.RESULTSET.equals(tag))
2906:                            throw new DriverSQLException(
2907:                                    getCurrentMethodName()
2908:                                            + ": Unexpected response for request "
2909:                                            + proc
2910:                                                    .getSqlShortForm(ABBREV_REQUEST_LENGTH),
2911:                                    recvEx);
2912:
2913:                        // Ok, we have a real non-null ResultSet, fetch it
2914:                        drs = new DriverResultSet(this );
2915:                        if (sequoiaUrl.isDebugEnabled())
2916:                            System.out.println("Retrieved ResultSet: " + drs);
2917:                    }
2918:
2919:                    // Now fetch the OUT parameters
2920:                    HashMap outParameters = fetchOutParameters();
2921:
2922:                    // Now fetch the named parameters
2923:                    HashMap namedParameters = fetchNamedParameters();
2924:
2925:                    List result = new ArrayList(3);
2926:                    result.add(drs);
2927:                    result.add(outParameters);
2928:                    result.add(namedParameters);
2929:                    return new ResultAndWarnings(result, sqlw);
2930:                } catch (RuntimeException e) {
2931:                    throw new DriverSQLException(getCurrentMethodName()
2932:                            + ": Error occured while request '"
2933:                            + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
2934:                            + "' was processed by Sequoia Controller", e);
2935:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
2936:                    try {
2937:                        reconnect();
2938:                        if (procIdIsSet) { // Controller handled the query, check if it was executed
2939:                            ResultAndWarnings result = retrieveExecuteQueryResultWithParameters(proc);
2940:                            if (result != null
2941:                                    && result.getResultList() != null)
2942:                                return result;
2943:                        }
2944:                        // At this point the query failed before any controller succeeded in
2945:                        // executing the query
2946:
2947:                        return callableStatementExecuteQuery(proc);
2948:                    } catch (DriverSQLException e1) {
2949:                        throw new DriverSQLException(
2950:                                "Connection lost while executing "
2951:                                        + getCurrentMethodName()
2952:                                        + " on procedure request '"
2953:                                        + proc
2954:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
2955:                                        + "' and automatic reconnect failed ("
2956:                                        + e1 + ")", e1);
2957:                    }
2958:                } catch (SerializableException se) {
2959:                    throw new DriverSQLException(se);
2960:                }
2961:            }
2962:
2963:            /**
2964:             * Call a stored procedure that performs an update.
2965:             * 
2966:             * @param proc the stored procedure call
2967:             * @return a List composed of an Integer (number of updated rows), an
2968:             *         <code>ArrayList</code> of OUT parameters, and a
2969:             *         <code>HashMap</code> of named parameters result objects.
2970:             * @exception DriverSQLException if an error occurs
2971:             */
2972:            protected synchronized ResultAndWarnings callableStatementExecuteUpdate(
2973:                    Request proc) throws DriverSQLException {
2974:                throwSQLExceptionIfClosed("Closed Connection cannot process request '"
2975:                        + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
2976:                beginTransactionIfNeeded();
2977:
2978:                boolean procIdIsSet = false;
2979:                try {
2980:                    setConnectionParametersOnRequest(proc);
2981:                    sendCommand(Commands.CallableStatementExecuteUpdateWithParameters);
2982:                    proc.sendToStream(socketOutput);
2983:                    socketOutput.flush();
2984:                    if (sequoiaUrl.isDebugEnabled())
2985:                        System.out.println("Executing "
2986:                                + getCurrentMethodName() + " with procedure '"
2987:                                + proc + "'");
2988:
2989:                    proc.setId(receiveLongOrException());
2990:                    procIdIsSet = true;
2991:                    if (!autoCommit)
2992:                        writeExecutedInTransaction = true;
2993:
2994:                    if (sequoiaUrl.isDebugEnabled())
2995:                        System.out.println("Received unique id " + proc.getId()
2996:                                + " for procedure '" + proc + "'");
2997:
2998:                    // Receive SQLWarnings
2999:                    SQLWarning sqlw = receiveSQLWarnings();
3000:
3001:                    // Receive update count
3002:                    Integer updateCount = new Integer(receiveIntOrException());
3003:
3004:                    // Now fetch the OUT parameters
3005:                    HashMap outParameters = fetchOutParameters();
3006:
3007:                    // Now fetch the named parameters
3008:                    HashMap namedParameters = fetchNamedParameters();
3009:
3010:                    List result = new ArrayList(3);
3011:                    result.add(updateCount);
3012:                    result.add(outParameters);
3013:                    result.add(namedParameters);
3014:                    return new ResultAndWarnings(result, sqlw);
3015:
3016:                } catch (SerializableException se) {
3017:                    throw new DriverSQLException(se);
3018:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
3019:                    try {
3020:                        reconnect();
3021:                        if (procIdIsSet) { // Controller handled the query, check if it was executed
3022:                            ResultAndWarnings result = retrieveExecuteUpdateResultWithParameters(proc);
3023:                            if (result != null
3024:                                    && result.getResultList() != null)
3025:                                return result;
3026:                        }
3027:                        // At this point the query failed before any controller succeeded in
3028:                        // executing the query
3029:
3030:                        return callableStatementExecuteUpdate(proc);
3031:                    } catch (DriverSQLException e1) {
3032:                        throw new DriverSQLException(
3033:                                "Connection lost while executing "
3034:                                        + getCurrentMethodName()
3035:                                        + " on procedure request '"
3036:                                        + proc
3037:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
3038:                                        + "' and automatic reconnect failed ("
3039:                                        + e1 + ")", e1);
3040:                    }
3041:                }
3042:            }
3043:
3044:            /**
3045:             * Call a stored procedure that returns a list of results.
3046:             * 
3047:             * @param proc the stored procedure call
3048:             * @return a List composed of 1. <code>List</code> of results, 2.
3049:             *         <code>ArrayList</code> of OUT parameters, and 3.
3050:             *         <code>HashMap</code> of named parameters result objects.
3051:             * @exception DriverSQLException if an error occurs
3052:             */
3053:            protected synchronized ResultAndWarnings callableStatementExecute(
3054:                    RequestWithResultSetParameters proc)
3055:                    throws DriverSQLException {
3056:                throwSQLExceptionIfClosed("Closed Connection cannot process request '"
3057:                        + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH) + "'");
3058:                beginTransactionIfNeeded();
3059:
3060:                boolean procIdIsSet = false;
3061:                try {
3062:                    setConnectionParametersOnRequest(proc);
3063:                    sendCommand(Commands.CallableStatementExecuteWithParameters);
3064:                    proc.sendToStream(socketOutput);
3065:                    socketOutput.flush();
3066:                    if (sequoiaUrl.isDebugEnabled())
3067:                        System.out.println("Executing "
3068:                                + getCurrentMethodName() + " with procedure '"
3069:                                + proc + "'");
3070:
3071:                    proc.setId(receiveLongOrException());
3072:                    procIdIsSet = true;
3073:                    if (!autoCommit)
3074:                        writeExecutedInTransaction = true;
3075:
3076:                    if (sequoiaUrl.isDebugEnabled())
3077:                        System.out.println("Received unique id " + proc.getId()
3078:                                + " for procedure '" + proc + "'");
3079:
3080:                    // Fetch warnings
3081:                    SQLWarning sqlw = receiveSQLWarnings();
3082:
3083:                    // Fetch results
3084:                    List resultList = fetchMultipleResultsFromStream(getCurrentMethodName());
3085:
3086:                    // Now fetch the OUT parameters
3087:                    HashMap outParameters = fetchOutParameters();
3088:
3089:                    // Now fetch the named parameters
3090:                    HashMap namedParameters = fetchNamedParameters();
3091:
3092:                    List result = new ArrayList(3);
3093:                    result.add(resultList);
3094:                    result.add(outParameters);
3095:                    result.add(namedParameters);
3096:                    return new ResultAndWarnings(result, sqlw);
3097:                } catch (RuntimeException e) {
3098:                    throw new DriverSQLException(getCurrentMethodName()
3099:                            + ": Error occured while request '"
3100:                            + proc.getSqlShortForm(ABBREV_REQUEST_LENGTH)
3101:                            + "' was processed by Sequoia Controller", e);
3102:                } catch (IOException e) { // Connection failed, try to reconnect and re-exec the query
3103:                    try {
3104:                        reconnect();
3105:                        if (procIdIsSet) { // Controller handled the query, check if it was executed
3106:                            ResultAndWarnings rww = retrieveExecuteResultWithParameters(proc);
3107:                            if (rww != null && rww.getResultList() != null)
3108:                                return rww;
3109:                        }
3110:                        // At this point the query failed before any controller succeeded in
3111:                        // executing the query
3112:
3113:                        return callableStatementExecute(proc);
3114:                    } catch (DriverSQLException e1) {
3115:                        throw new DriverSQLException(
3116:                                "Connection lost while executing "
3117:                                        + getCurrentMethodName()
3118:                                        + " with procedure request'"
3119:                                        + proc
3120:                                                .getSqlShortForm(ABBREV_REQUEST_LENGTH)
3121:                                        + "' and automatic reconnect failed ("
3122:                                        + e1 + ")", e1);
3123:                    }
3124:                } catch (SerializableException e) {
3125:                    throw new DriverSQLException(e);
3126:                }
3127:            }
3128:
3129:            //
3130:            // Database Metadata methods
3131:            //
3132:
3133:            /**
3134:             * Closes the remote ResultSet given its cursor name.
3135:             * 
3136:             * @param cursorName cursor name of the ResultSet to close.
3137:             * @throws SQLException if an error occurs
3138:             */
3139:            protected synchronized void closeRemoteResultSet(String cursorName)
3140:                    throws SQLException {
3141:                throwSQLExceptionIfClosed();
3142:                try {
3143:                    sendCommand(Commands.CloseRemoteResultSet);
3144:                    socketOutput.writeLongUTF(cursorName);
3145:                    socketOutput.flush();
3146:                    if (sequoiaUrl.isDebugEnabled())
3147:                        System.out.println("Closing remote ResultSet");
3148:
3149:                    receiveBooleanOrException();
3150:                } catch (SerializableException se) {
3151:                    throw new DriverSQLException(se);
3152:                } catch (IOException e) {
3153:                    throw wrapIOExceptionInDriverSQLException(
3154:                            getCurrentMethodName(), e);
3155:                }
3156:            }
3157:
3158:            /**
3159:             * @see java.sql.DatabaseMetaData#getAttributes(java.lang.String,
3160:             *      java.lang.String, java.lang.String, java.lang.String)
3161:             */
3162:            protected synchronized ResultSet getAttributes(String catalog,
3163:                    String schemaPattern, String typeNamePattern,
3164:                    String attributeNamePattern) throws DriverSQLException {
3165:                throwSQLExceptionIfClosed();
3166:                try {
3167:                    sendCommand(Commands.DatabaseMetaDataGetAttributes);
3168:                    socketOutput.writeLongUTF(catalog);
3169:                    socketOutput.writeLongUTF(schemaPattern);
3170:                    socketOutput.writeLongUTF(typeNamePattern);
3171:                    socketOutput.writeLongUTF(attributeNamePattern);
3172:                    socketOutput.flush();
3173:
3174:                    if (sequoiaUrl.isDebugEnabled())
3175:                        System.out.println(getCurrentMethodName() + "("
3176:                                + catalog + "," + schemaPattern + ","
3177:                                + typeNamePattern + "," + attributeNamePattern
3178:                                + ")");
3179:
3180:                    return receiveResultSet(getCurrentMethodName());
3181:                } catch (SerializableException e) {
3182:                    throw new DriverSQLException(e);
3183:                } catch (IOException e) {
3184:                    try {
3185:                        reconnect();
3186:                        return getAttributes(catalog, schemaPattern,
3187:                                typeNamePattern, attributeNamePattern);
3188:                    } catch (DriverSQLException e1) {
3189:                        throw new DriverSQLException(
3190:                                "Connection lost while executing "
3191:                                        + getCurrentMethodName()
3192:                                        + " and automatic reconnect failed ",
3193:                                e1);
3194:                    }
3195:                }
3196:            }
3197:
3198:            /**
3199:             * @see java.sql.DatabaseMetaData#getBestRowIdentifier(java.lang.String,
3200:             *      java.lang.String, java.lang.String, int, boolean)
3201:             */
3202:            protected synchronized ResultSet getBestRowIdentifier(
3203:                    String catalog, String schema, String table, int scope,
3204:                    boolean nullable) throws DriverSQLException {
3205:                throwSQLExceptionIfClosed();
3206:                try {
3207:                    sendCommand(Commands.DatabaseMetaDataGetBestRowIdentifier);
3208:                    socketOutput.writeLongUTF(catalog);
3209:                    socketOutput.writeLongUTF(schema);
3210:                    socketOutput.writeLongUTF(table);
3211:                    socketOutput.writeInt(scope);
3212:                    socketOutput.writeBoolean(nullable);
3213:                    socketOutput.flush();
3214:
3215:                    if (sequoiaUrl.isDebugEnabled())
3216:                        System.out.println(getCurrentMethodName() + "("
3217:                                + catalog + "," + schema + "," + table + ","
3218:                                + scope + "," + nullable + ")");
3219:
3220:                    return receiveResultSet(getCurrentMethodName());
3221:                } catch (SerializableException e) {
3222:                    throw new DriverSQLException(e);
3223:                } catch (IOException e) {
3224:                    try {
3225:                        reconnect();
3226:                        return getBestRowIdentifier(catalog, schema, table,
3227:                                scope, nullable);
3228:                    } catch (DriverSQLException e1) {
3229:                        throw new DriverSQLException(
3230:                                "Connection lost while executing "
3231:                                        + getCurrentMethodName()
3232:                                        + " and automatic reconnect failed ",
3233:                                e1);
3234:                    }
3235:                }
3236:            }
3237:
3238:            /**
3239:             * @see java.sql.DatabaseMetaData#getColumnPrivileges(java.lang.String,
3240:             *      java.lang.String, java.lang.String, java.lang.String)
3241:             */
3242:            protected synchronized ResultSet getColumnPrivileges(
3243:                    String catalog, String schemaPattern, String tableName,
3244:                    String columnNamePattern) throws DriverSQLException {
3245:                throwSQLExceptionIfClosed();
3246:                try {
3247:                    sendCommand(Commands.DatabaseMetaDataGetColumnPrivileges);
3248:                    socketOutput.writeLongUTF(catalog);
3249:                    socketOutput.writeLongUTF(schemaPattern);
3250:                    socketOutput.writeLongUTF(tableName);
3251:                    socketOutput.writeLongUTF(columnNamePattern);
3252:                    socketOutput.flush();
3253:
3254:                    if (sequoiaUrl.isDebugEnabled())
3255:                        System.out.println(getCurrentMethodName() + "("
3256:                                + catalog + "," + schemaPattern + ","
3257:                                + tableName + "," + columnNamePattern + ")");
3258:
3259:                    return receiveResultSet(getCurrentMethodName());
3260:                } catch (SerializableException e) {
3261:                    throw new DriverSQLException(e);
3262:                } catch (IOException e) {
3263:                    try {
3264:                        reconnect();
3265:                        return getColumnPrivileges(catalog, schemaPattern,
3266:                                tableName, columnNamePattern);
3267:                    } catch (DriverSQLException e1) {
3268:                        throw new DriverSQLException(
3269:                                "Connection lost while executing "
3270:                                        + getCurrentMethodName()
3271:                                        + " and automatic reconnect failed ",
3272:                                e1);
3273:                    }
3274:                }
3275:            }
3276:
3277:            /**
3278:             * @see java.sql.DatabaseMetaData#getColumns(java.lang.String,
3279:             *      java.lang.String, java.lang.String, java.lang.String)
3280:             */
3281:            protected synchronized ResultSet getColumns(String catalog,
3282:                    String schemaPattern, String tableNamePattern,
3283:                    String columnNamePattern) throws DriverSQLException {
3284:                throwSQLExceptionIfClosed();
3285:                try {
3286:                    sendCommand(Commands.DatabaseMetaDataGetColumns);
3287:                    socketOutput.writeLongUTF(catalog);
3288:                    socketOutput.writeLongUTF(schemaPattern);
3289:                    socketOutput.writeLongUTF(tableNamePattern);
3290:                    socketOutput.writeLongUTF(columnNamePattern);
3291:                    socketOutput.flush();
3292:
3293:                    if (sequoiaUrl.isDebugEnabled())
3294:                        System.out.println(getCurrentMethodName() + "("
3295:                                + catalog + "," + schemaPattern + ","
3296:                                + tableNamePattern + "," + columnNamePattern
3297:                                + ")");
3298:
3299:                    return receiveResultSet(getCurrentMethodName());
3300:                } catch (SerializableException e) {
3301:                    throw new DriverSQLException(e);
3302:                } catch (IOException e) {
3303:                    try {
3304:                        reconnect();
3305:                        return getColumns(catalog, schemaPattern,
3306:                                tableNamePattern, columnNamePattern);
3307:                    } catch (DriverSQLException e1) {
3308:                        throw new DriverSQLException(
3309:                                "Connection lost while executing "
3310:                                        + getCurrentMethodName()
3311:                                        + " and automatic reconnect failed ",
3312:                                e1);
3313:                    }
3314:                }
3315:            }
3316:
3317:            /**
3318:             * Get the Sequoia controller version number.
3319:             * 
3320:             * @return a String containing the controller version
3321:             * @exception DriverSQLException if an error occurs
3322:             */
3323:            protected synchronized String getControllerVersionNumber()
3324:                    throws DriverSQLException {
3325:                throwSQLExceptionIfClosed();
3326:                try {
3327:                    sendCommand(Commands.GetControllerVersionNumber);
3328:                    socketOutput.flush();
3329:
3330:                    if (sequoiaUrl.isDebugEnabled())
3331:                        System.out.println("Executing "
3332:                                + getCurrentMethodName());
3333:
3334:                    return receiveStringOrException();
3335:                } catch (SerializableException e) {
3336:                    throw new DriverSQLException(e);
3337:                } catch (IOException e) {
3338:                    try {
3339:                        reconnect();
3340:                        return getControllerVersionNumber();
3341:                    } catch (DriverSQLException e1) {
3342:                        throw new DriverSQLException(
3343:                                "Connection lost while executing "
3344:                                        + getCurrentMethodName()
3345:                                        + " and automatic reconnect failed ",
3346:                                e1);
3347:                    }
3348:                }
3349:            }
3350:
3351:            /**
3352:             * @see java.sql.DatabaseMetaData#getCrossReference(java.lang.String,
3353:             *      java.lang.String, java.lang.String, java.lang.String,
3354:             *      java.lang.String, java.lang.String)
3355:             */
3356:            protected synchronized ResultSet getCrossReference(
3357:                    String primaryCatalog, String primarySchema,
3358:                    String primaryTable, String foreignCatalog,
3359:                    String foreignSchema, String foreignTable)
3360:                    throws DriverSQLException {
3361:                throwSQLExceptionIfClosed();
3362:                try {
3363:                    sendCommand(Commands.DatabaseMetaDataGetCrossReference);
3364:                    socketOutput.writeLongUTF(primaryCatalog);
3365:                    socketOutput.writeLongUTF(primarySchema);
3366:                    socketOutput.writeLongUTF(primaryTable);
3367:                    socketOutput.writeLongUTF(foreignCatalog);
3368:                    socketOutput.writeLongUTF(foreignSchema);
3369:                    socketOutput.writeLongUTF(foreignTable);
3370:                    socketOutput.flush();
3371:
3372:                    if (sequoiaUrl.isDebugEnabled())
3373:                        System.out.println(getCurrentMethodName() + "("
3374:                                + primaryCatalog + "," + primarySchema + ","
3375:                                + primaryTable + "," + foreignCatalog + ","
3376:                                + foreignSchema + "," + foreignTable + ")");
3377:
3378:                    return receiveResultSet(getCurrentMethodName());
3379:                } catch (SerializableException e) {
3380:                    throw new DriverSQLException(e);
3381:                } catch (IOException e) {
3382:                    try {
3383:                        reconnect();
3384:                        return getCrossReference(primaryCatalog, primarySchema,
3385:                                primaryTable, foreignCatalog, foreignSchema,
3386:                                foreignTable);
3387:                    } catch (DriverSQLException e1) {
3388:                        throw new DriverSQLException(
3389:                                "Connection lost while executing "
3390:                                        + getCurrentMethodName()
3391:                                        + " and automatic reconnect failed ",
3392:                                e1);
3393:                    }
3394:                }
3395:            }
3396:
3397:            /**
3398:             * @see DatabaseMetaData#getDatabaseProductName()
3399:             */
3400:            protected synchronized String getDatabaseProductName()
3401:                    throws DriverSQLException {
3402:                throwSQLExceptionIfClosed();
3403:                try {
3404:                    sendCommand(Commands.DatabaseMetaDataGetDatabaseProductName);
3405:                    socketOutput.flush();
3406:
3407:                    if (sequoiaUrl.isDebugEnabled())
3408:                        System.out.println(getCurrentMethodName());
3409:
3410:                    return receiveStringOrException();
3411:                } catch (SerializableException e) {
3412:                    throw new DriverSQLException(e);
3413:                } catch (IOException e) {
3414:                    try {
3415:                        reconnect();
3416:                        return getDatabaseProductName();
3417:                    } catch (DriverSQLException e1) {
3418:                        throw new DriverSQLException(
3419:                                "Connection lost while executing "
3420:                                        + getCurrentMethodName()
3421:                                        + " and automatic reconnect failed ",
3422:                                e1);
3423:                    }
3424:                }
3425:            }
3426:
3427:            /**
3428:             * @see java.sql.DatabaseMetaData#getExportedKeys(java.lang.String,
3429:             *      java.lang.String, java.lang.String)
3430:             */
3431:            protected synchronized ResultSet getExportedKeys(String catalog,
3432:                    String schema, String table) throws DriverSQLException {
3433:                throwSQLExceptionIfClosed();
3434:                try {
3435:                    sendCommand(Commands.DatabaseMetaDataGetExportedKeys);
3436:                    socketOutput.writeLongUTF(catalog);
3437:                    socketOutput.writeLongUTF(schema);
3438:                    socketOutput.writeLongUTF(table);
3439:                    socketOutput.flush();
3440:
3441:                    if (sequoiaUrl.isDebugEnabled())
3442:                        System.out.println(getCurrentMethodName() + "("
3443:                                + catalog + "," + schema + "," + table + ")");
3444:
3445:                    return receiveResultSet(getCurrentMethodName());
3446:                } catch (SerializableException e) {
3447:                    throw new DriverSQLException(e);
3448:                } catch (IOException e) {
3449:                    try {
3450:                        reconnect();
3451:                        return getExportedKeys(catalog, schema, table);
3452:                    } catch (DriverSQLException e1) {
3453:                        throw new DriverSQLException(
3454:                                "Connection lost while executing "
3455:                                        + getCurrentMethodName()
3456:                                        + " and automatic reconnect failed ",
3457:                                e1);
3458:                    }
3459:                }
3460:            }
3461:
3462:            /**
3463:             * @see java.sql.DatabaseMetaData#getImportedKeys(java.lang.String,
3464:             *      java.lang.String, java.lang.String)
3465:             */
3466:            protected synchronized ResultSet getImportedKeys(String catalog,
3467:                    String schema, String table) throws DriverSQLException {
3468:                throwSQLExceptionIfClosed();
3469:                try {
3470:                    sendCommand(Commands.DatabaseMetaDataGetImportedKeys);
3471:                    socketOutput.writeLongUTF(catalog);
3472:                    socketOutput.writeLongUTF(schema);
3473:                    socketOutput.writeLongUTF(table);
3474:                    socketOutput.flush();
3475:
3476:                    if (sequoiaUrl.isDebugEnabled())
3477:                        System.out.println(getCurrentMethodName() + "("
3478:                                + catalog + "," + schema + "," + table + ")");
3479:
3480:                    return receiveResultSet(getCurrentMethodName());
3481:                } catch (SerializableException e) {
3482:                    throw new DriverSQLException(e);
3483:                } catch (IOException e) {
3484:                    try {
3485:                        reconnect();
3486:                        return getImportedKeys(catalog, schema, table);
3487:                    } catch (DriverSQLException e1) {
3488:                        throw new DriverSQLException(
3489:                                "Connection lost while executing "
3490:                                        + getCurrentMethodName()
3491:                                        + " and automatic reconnect failed ",
3492:                                e1);
3493:                    }
3494:                }
3495:            }
3496:
3497:            /**
3498:             * @see java.sql.DatabaseMetaData#getIndexInfo(java.lang.String,
3499:             *      java.lang.String, java.lang.String, boolean, boolean)
3500:             */
3501:            protected synchronized ResultSet getIndexInfo(String catalog,
3502:                    String schema, String table, boolean unique,
3503:                    boolean approximate) throws DriverSQLException {
3504:                throwSQLExceptionIfClosed();
3505:                try {
3506:                    sendCommand(Commands.DatabaseMetaDataGetIndexInfo);
3507:                    socketOutput.writeLongUTF(catalog);
3508:                    socketOutput.writeLongUTF(schema);
3509:                    socketOutput.writeLongUTF(table);
3510:                    socketOutput.writeBoolean(unique);
3511:                    socketOutput.writeBoolean(approximate);
3512:                    socketOutput.flush();
3513:
3514:                    if (sequoiaUrl.isDebugEnabled())
3515:                        System.out.println(getCurrentMethodName() + "("
3516:                                + catalog + "," + schema + "," + table + ","
3517:                                + unique + "," + approximate + ")");
3518:
3519:                    return receiveResultSet(getCurrentMethodName());
3520:                } catch (SerializableException e) {
3521:                    throw new DriverSQLException(e);
3522:                } catch (IOException e) {
3523:                    try {
3524:                        reconnect();
3525:                        return getIndexInfo(catalog, schema, table, unique,
3526:                                approximate);
3527:                    } catch (DriverSQLException e1) {
3528:                        throw new DriverSQLException(
3529:                                "Connection lost while executing "
3530:                                        + getCurrentMethodName()
3531:                                        + " and automatic reconnect failed ",
3532:                                e1);
3533:                    }
3534:                }
3535:            }
3536:
3537:            /**
3538:             * @param sqlTemplate sql template of the PreparedStatement
3539:             * @see java.sql.PreparedStatement#getMetaData()
3540:             */
3541:            protected synchronized ResultSetMetaData preparedStatementGetMetaData(
3542:                    String sqlTemplate) throws DriverSQLException {
3543:                throwSQLExceptionIfClosed();
3544:                try {
3545:                    sendCommand(Commands.PreparedStatementGetMetaData);
3546:                    socketOutput.writeLongUTF(sqlTemplate);
3547:                    socketOutput.flush();
3548:
3549:                    if (sequoiaUrl.isDebugEnabled())
3550:                        System.out.println(getCurrentMethodName() + "()");
3551:
3552:                    return receiveResultSet(getCurrentMethodName())
3553:                            .getMetaData();
3554:                } catch (SerializableException e) {
3555:                    throw new DriverSQLException(e);
3556:                } catch (SQLException e) {
3557:                    throw new DriverSQLException(e);
3558:                } catch (IOException e) {
3559:                    try {
3560:                        reconnect();
3561:                        return preparedStatementGetMetaData(sqlTemplate);
3562:                    } catch (DriverSQLException e1) {
3563:                        throw new DriverSQLException(
3564:                                "Connection lost while executing "
3565:                                        + getCurrentMethodName()
3566:                                        + " and automatic reconnect failed ",
3567:                                e1);
3568:                    }
3569:                }
3570:            }
3571:
3572:            /**
3573:             * @see java.sql.DatabaseMetaData#getPrimaryKeys(java.lang.String,
3574:             *      java.lang.String, java.lang.String)
3575:             */
3576:            protected synchronized ResultSet getPrimaryKeys(String catalog,
3577:                    String schemaPattern, String tableNamePattern)
3578:                    throws DriverSQLException {
3579:                throwSQLExceptionIfClosed();
3580:                try {
3581:                    sendCommand(Commands.DatabaseMetaDataGetPrimaryKeys);
3582:                    socketOutput.writeLongUTF(catalog);
3583:                    socketOutput.writeLongUTF(schemaPattern);
3584:                    socketOutput.writeLongUTF(tableNamePattern);
3585:                    socketOutput.flush();
3586:
3587:                    if (sequoiaUrl.isDebugEnabled())
3588:                        System.out.println(getCurrentMethodName() + "("
3589:                                + catalog + "," + schemaPattern + ","
3590:                                + tableNamePattern + ")");
3591:
3592:                    return receiveResultSet(getCurrentMethodName());
3593:                } catch (SerializableException e) {
3594:                    throw new DriverSQLException(e);
3595:                } catch (IOException e) {
3596:                    try {
3597:                        reconnect();
3598:                        return getPrimaryKeys(catalog, schemaPattern,
3599:                                tableNamePattern);
3600:                    } catch (DriverSQLException e1) {
3601:                        throw new DriverSQLException(
3602:                                "Connection lost while executing "
3603:                                        + getCurrentMethodName()
3604:                                        + " and automatic reconnect failed ",
3605:                                e1);
3606:                    }
3607:                }
3608:            }
3609:
3610:            protected synchronized java.sql.ResultSet getProcedures(
3611:                    String catalog, String schemaPattern,
3612:                    String procedureNamePattern) throws DriverSQLException {
3613:                throwSQLExceptionIfClosed();
3614:                try {
3615:                    sendCommand(Commands.DatabaseMetaDataGetProcedures);
3616:                    socketOutput.writeLongUTF(catalog);
3617:                    socketOutput.writeLongUTF(schemaPattern);
3618:                    socketOutput.writeLongUTF(procedureNamePattern);
3619:                    socketOutput.flush();
3620:
3621:                    if (sequoiaUrl.isDebugEnabled())
3622:                        System.out.println(getCurrentMethodName() + "("
3623:                                + catalog + "," + schemaPattern + ","
3624:                                + procedureNamePattern + ")");
3625:
3626:                    return receiveResultSet(getCurrentMethodName());
3627:                } catch (SerializableException e) {
3628:                    throw new DriverSQLException(e);
3629:                } catch (IOException e) {
3630:                    try {
3631:                        reconnect();
3632:                        return getProcedures(catalog, schemaPattern,
3633:                                procedureNamePattern);
3634:                    } catch (DriverSQLException e1) {
3635:                        throw new DriverSQLException(
3636:                                "Connection lost while executing "
3637:                                        + getCurrentMethodName()
3638:                                        + " and automatic reconnect failed ",
3639:                                e1);
3640:                    }
3641:                }
3642:            }
3643:
3644:            protected synchronized java.sql.ResultSet getProcedureColumns(
3645:                    String catalog, String schemaPattern,
3646:                    String procedureNamePattern, String columnNamePattern)
3647:                    throws DriverSQLException {
3648:                throwSQLExceptionIfClosed();
3649:                try {
3650:                    sendCommand(Commands.DatabaseMetaDataGetProcedureColumns);
3651:                    socketOutput.writeLongUTF(catalog);
3652:                    socketOutput.writeLongUTF(schemaPattern);
3653:                    socketOutput.writeLongUTF(procedureNamePattern);
3654:                    socketOutput.writeLongUTF(columnNamePattern);
3655:                    socketOutput.flush();
3656:
3657:                    if (sequoiaUrl.isDebugEnabled())
3658:                        System.out.println(getCurrentMethodName() + "("
3659:                                + catalog + "," + schemaPattern + ","
3660:                                + procedureNamePattern + ","
3661:                                + columnNamePattern + ")");
3662:
3663:                    return receiveResultSet(getCurrentMethodName());
3664:                } catch (SerializableException e) {
3665:                    throw new DriverSQLException(e);
3666:                } catch (IOException e) {
3667:                    try {
3668:                        reconnect();
3669:                        return getProcedureColumns(catalog, schemaPattern,
3670:                                procedureNamePattern, columnNamePattern);
3671:                    } catch (DriverSQLException e1) {
3672:                        throw new DriverSQLException(
3673:                                "Connection lost while executing "
3674:                                        + getCurrentMethodName()
3675:                                        + " and automatic reconnect failed ",
3676:                                e1);
3677:                    }
3678:                }
3679:            }
3680:
3681:            /**
3682:             * @see java.sql.DatabaseMetaData#getSchemas()
3683:             */
3684:            protected synchronized ResultSet getSchemas()
3685:                    throws DriverSQLException {
3686:                throwSQLExceptionIfClosed();
3687:
3688:                try {
3689:                    sendCommand(Commands.DatabaseMetaDataGetSchemas);
3690:                    socketOutput.flush();
3691:
3692:                    if (sequoiaUrl.isDebugEnabled())
3693:                        System.out.println(getCurrentMethodName());
3694:
3695:                    return receiveResultSet(getCurrentMethodName());
3696:                } catch (SerializableException e) {
3697:                    throw new DriverSQLException(e);
3698:                } catch (IOException e) {
3699:                    try {
3700:                        reconnect();
3701:                        return getSchemas();
3702:                    } catch (DriverSQLException e1) {
3703:                        throw new DriverSQLException(
3704:                                "Connection lost while executing "
3705:                                        + getCurrentMethodName()
3706:                                        + " and automatic reconnect failed ",
3707:                                e1);
3708:                    }
3709:                }
3710:            }
3711:
3712:            /**
3713:             * @see java.sql.DatabaseMetaData#getSuperTables(java.lang.String,
3714:             *      java.lang.String, java.lang.String)
3715:             */
3716:            protected synchronized ResultSet getSuperTables(String catalog,
3717:                    String schemaPattern, String tableNamePattern)
3718:                    throws DriverSQLException {
3719:                throwSQLExceptionIfClosed();
3720:                try {
3721:                    sendCommand(Commands.DatabaseMetaDataGetSuperTables);
3722:                    socketOutput.writeLongUTF(catalog);
3723:                    socketOutput.writeLongUTF(schemaPattern);
3724:                    socketOutput.writeLongUTF(tableNamePattern);
3725:                    socketOutput.flush();
3726:
3727:                    if (sequoiaUrl.isDebugEnabled())
3728:                        System.out.println(getCurrentMethodName() + "("
3729:                                + catalog + "," + schemaPattern + ","
3730:                                + tableNamePattern + ")");
3731:
3732:                    return receiveResultSet(getCurrentMethodName());
3733:                } catch (SerializableException e) {
3734:                    throw new DriverSQLException(e);
3735:                } catch (IOException e) {
3736:                    try {
3737:                        reconnect();
3738:                        return getSuperTables(catalog, schemaPattern,
3739:                                tableNamePattern);
3740:                    } catch (DriverSQLException e1) {
3741:                        throw new DriverSQLException(
3742:                                "Connection lost while executing "
3743:                                        + getCurrentMethodName()
3744:                                        + " and automatic reconnect failed ",
3745:                                e1);
3746:                    }
3747:                }
3748:            }
3749:
3750:            /**
3751:             * @see java.sql.DatabaseMetaData#getSuperTypes(java.lang.String,
3752:             *      java.lang.String, java.lang.String)
3753:             */
3754:            protected synchronized ResultSet getSuperTypes(String catalog,
3755:                    String schemaPattern, String typeNamePattern)
3756:                    throws DriverSQLException {
3757:                throwSQLExceptionIfClosed();
3758:                try {
3759:                    sendCommand(Commands.DatabaseMetaDataGetSuperTypes);
3760:                    socketOutput.writeLongUTF(catalog);
3761:                    socketOutput.writeLongUTF(schemaPattern);
3762:                    socketOutput.writeLongUTF(typeNamePattern);
3763:                    socketOutput.flush();
3764:
3765:                    if (sequoiaUrl.isDebugEnabled())
3766:                        System.out.println(getCurrentMethodName() + "("
3767:                                + catalog + "," + schemaPattern + ","
3768:                                + typeNamePattern + ")");
3769:
3770:                    return receiveResultSet(getCurrentMethodName());
3771:                } catch (SerializableException e) {
3772:                    throw new DriverSQLException(e);
3773:                } catch (IOException e) {
3774:                    try {
3775:                        reconnect();
3776:                        return getSuperTypes(catalog, schemaPattern,
3777:                                typeNamePattern);
3778:                    } catch (DriverSQLException e1) {
3779:                        throw new DriverSQLException(
3780:                                "Connection lost while executing getSuperTypes and automatic reconnect failed ",
3781:                                e1);
3782:                    }
3783:                }
3784:            }
3785:
3786:            /**
3787:             * Retrieve a static metadata from the controller.
3788:             * 
3789:             * @param key the "getXXX(Y,Z,...)" hash key of the metadata query
3790:             * @return an Object that will be an <tt>Integer</tt> or <tt>Boolean</tt>
3791:             *         or <tt>String</tt>
3792:             * @throws DriverSQLException if fails
3793:             * @see org.continuent.sequoia.controller.virtualdatabase.VirtualDatabaseWorkerThread#databaseStaticMetadata()
3794:             * @see org.continuent.sequoia.controller.backend.DatabaseBackendMetaData#retrieveDatabaseMetadata()
3795:             */
3796:            protected synchronized Object getStaticMetadata(String key)
3797:                    throws DriverSQLException {
3798:                throwSQLExceptionIfClosed();
3799:                try {
3800:                    sendCommand(Commands.DatabaseStaticMetadata);
3801:                    socketOutput.writeLongUTF(key);
3802:                    socketOutput.flush();
3803:                    if (sequoiaUrl.isDebugEnabled())
3804:                        System.out.println("Getting " + key + " metadata");
3805:
3806:                    TypeTag tag = new TypeTag(socketInput);
3807:
3808:                    if (TypeTag.EXCEPTION.equals(tag))
3809:                        throw new DriverSQLException(receiveException());
3810:                    else {
3811:                        tag = new TypeTag(socketInput);
3812:                        Object result = SQLDataSerialization.getSerializer(tag)
3813:                                .receiveFromStream(socketInput);
3814:                        return result;
3815:                    }
3816:                } catch (IOException e) {
3817:                    try {
3818:                        reconnect();
3819:                        return getStaticMetadata(key);
3820:                    } catch (DriverSQLException e1) {
3821:                        throw new DriverSQLException(
3822:                                "Connection lost while executing "
3823:                                        + getCurrentMethodName()
3824:                                        + " and automatic reconnect failed ",
3825:                                e1);
3826:                    }
3827:                }
3828:            }
3829:
3830:            /**
3831:             * Gets a description of the access rights for each table available in a
3832:             * catalog. Note that a table privilege applies to one or more columns in the
3833:             * table. It would be wrong to assume that this priviledge applies to all
3834:             * columns (this may be true for some systems but is not true for all.) Only
3835:             * privileges matching the schema and table name criteria are returned. They
3836:             * are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
3837:             * 
3838:             * @param catalog a catalog name; "" retrieves those without a catalog; null
3839:             *          means drop catalog name from the selection criteria
3840:             * @param schemaPattern a schema name pattern; "" retrieves those without a
3841:             *          schema
3842:             * @param tableNamePattern a table name pattern
3843:             * @return <code>ResultSet</code> each row is a table privilege description
3844:             * @throws DriverSQLException if a database access error occurs
3845:             */
3846:            protected synchronized ResultSet getTablePrivileges(String catalog,
3847:                    String schemaPattern, String tableNamePattern)
3848:                    throws DriverSQLException {
3849:                throwSQLExceptionIfClosed();
3850:                try {
3851:                    sendCommand(Commands.DatabaseMetaDataGetTablePrivileges);
3852:                    socketOutput.writeLongUTF(catalog);
3853:                    socketOutput.writeLongUTF(schemaPattern);
3854:                    socketOutput.writeLongUTF(tableNamePattern);
3855:                    socketOutput.flush();
3856:
3857:                    if (sequoiaUrl.isDebugEnabled())
3858:                        System.out.println(getCurrentMethodName() + "("
3859:                                + catalog + "," + schemaPattern + ","
3860:                                + tableNamePattern + ")");
3861:
3862:                    return receiveResultSet(getCurrentMethodName());
3863:                } catch (SerializableException e) {
3864:                    throw new DriverSQLException(e);
3865:                } catch (IOException e) {
3866:                    try {
3867:                        reconnect();
3868:                        return getTablePrivileges(catalog, schemaPattern,
3869:                                tableNamePattern);
3870:                    } catch (DriverSQLException e1) {
3871:                        throw new DriverSQLException(
3872:                                "Connection lost while executing "
3873:                                        + getCurrentMethodName()
3874:                                        + " and automatic reconnect failed ",
3875:                                e1);
3876:                    }
3877:                }
3878:            }
3879:
3880:            /**
3881:             * @see org.continuent.sequoia.driver.DatabaseMetaData#getTables(String,
3882:             *      String, String, String[])
3883:             */
3884:            protected synchronized ResultSet getTables(String catalog,
3885:                    String schemaPattern, String tableNamePattern,
3886:                    String[] types) throws DriverSQLException {
3887:                throwSQLExceptionIfClosed();
3888:                try {
3889:                    sendCommand(Commands.DatabaseMetaDataGetTables);
3890:                    socketOutput.writeLongUTF(catalog);
3891:                    socketOutput.writeLongUTF(schemaPattern);
3892:                    socketOutput.writeLongUTF(tableNamePattern);
3893:
3894:                    if (null == types)
3895:                        socketOutput.writeBoolean(false);
3896:                    else {
3897:                        socketOutput.writeBoolean(true);
3898:                        socketOutput.writeInt(types.length);
3899:                        for (int i = 0; i < types.length; i++)
3900:                            socketOutput.writeLongUTF(types[i]);
3901:                    }
3902:                    socketOutput.flush();
3903:
3904:                    if (sequoiaUrl.isDebugEnabled())
3905:                        System.out.println(getCurrentMethodName() + "("
3906:                                + catalog + "," + schemaPattern + ","
3907:                                + tableNamePattern + "," + types + ")");
3908:
3909:                    return receiveResultSet(getCurrentMethodName());
3910:                } catch (SerializableException e) {
3911:                    throw new DriverSQLException(e);
3912:                } catch (IOException e) {
3913:                    try {
3914:                        reconnect();
3915:                        return getTables(catalog, schemaPattern,
3916:                                tableNamePattern, types);
3917:                    } catch (DriverSQLException e1) {
3918:                        throw new DriverSQLException(
3919:                                "Connection lost while executing "
3920:                                        + getCurrentMethodName()
3921:                                        + " and automatic reconnect failed ",
3922:                                e1);
3923:                    }
3924:                }
3925:            }
3926:
3927:            /**
3928:             * Gets the table types available in this database. The results are ordered by
3929:             * table type.
3930:             * 
3931:             * @return <code>ResultSet</code> each row has a single String column that
3932:             *         is a catalog name
3933:             * @throws SQLException if a database error occurs
3934:             */
3935:            protected synchronized ResultSet getTableTypes()
3936:                    throws SQLException {
3937:                throwSQLExceptionIfClosed();
3938:                try {
3939:                    sendCommand(Commands.DatabaseMetaDataGetTableTypes);
3940:                    socketOutput.flush();
3941:
3942:                    if (sequoiaUrl.isDebugEnabled())
3943:                        System.out.println(getCurrentMethodName());
3944:
3945:                    return receiveResultSet(getCurrentMethodName());
3946:                } catch (SerializableException e) {
3947:                    throw new DriverSQLException(e);
3948:                } catch (IOException e) {
3949:                    try {
3950:                        reconnect();
3951:                        return getTableTypes();
3952:                    } catch (DriverSQLException e1) {
3953:                        throw new DriverSQLException(
3954:                                "Connection lost while executing "
3955:                                        + getCurrentMethodName()
3956:                                        + " and automatic reconnect failed ",
3957:                                e1);
3958:                    }
3959:                }
3960:            }
3961:
3962:            /**
3963:             * @see java.sql.DatabaseMetaData#getTypeInfo()
3964:             */
3965:            protected synchronized ResultSet getTypeInfo()
3966:                    throws DriverSQLException {
3967:                throwSQLExceptionIfClosed();
3968:                try {
3969:                    sendCommand(Commands.DatabaseMetaDataGetTypeInfo);
3970:                    socketOutput.flush();
3971:
3972:                    if (sequoiaUrl.isDebugEnabled())
3973:                        System.out.println(getCurrentMethodName() + "()");
3974:
3975:                    return receiveResultSet(getCurrentMethodName());
3976:                } catch (SerializableException e) {
3977:                    throw new DriverSQLException(e);
3978:                } catch (IOException e) {
3979:                    try {
3980:                        reconnect();
3981:                        return getTypeInfo();
3982:                    } catch (DriverSQLException e1) {
3983:                        throw new DriverSQLException(
3984:                                "Connection lost while executing "
3985:                                        + getCurrentMethodName()
3986:                                        + " and automatic reconnect failed ",
3987:                                e1);
3988:                    }
3989:                }
3990:            }
3991:
3992:            /**
3993:             * @see java.sql.DatabaseMetaData#getUDTs(java.lang.String, java.lang.String,
3994:             *      java.lang.String, int[])
3995:             */
3996:            protected synchronized ResultSet getUDTs(String catalog,
3997:                    String schemaPattern, String typeNamePattern, int[] types)
3998:                    throws DriverSQLException {
3999:                throwSQLExceptionIfClosed();
4000:                try {
4001:                    sendCommand(Commands.DatabaseMetaDataGetUDTs);
4002:                    socketOutput.writeLongUTF(catalog);
4003:                    socketOutput.writeLongUTF(schemaPattern);
4004:                    socketOutput.writeLongUTF(typeNamePattern);
4005:
4006:                    if (null == types)
4007:                        socketOutput.writeBoolean(false);
4008:                    else {
4009:                        socketOutput.writeBoolean(true);
4010:                        socketOutput.writeInt(types.length);
4011:                        for (int i = 0; i < types.length; i++)
4012:                            socketOutput.writeInt(types[i]);
4013:                    }
4014:                    socketOutput.flush();
4015:
4016:                    if (sequoiaUrl.isDebugEnabled())
4017:                        System.out.println(getCurrentMethodName() + "("
4018:                                + catalog + "," + schemaPattern + ","
4019:                                + typeNamePattern + "," + types + ")");
4020:
4021:                    return receiveResultSet(getCurrentMethodName());
4022:                } catch (SerializableException e) {
4023:                    throw new DriverSQLException(e);
4024:                } catch (IOException e) {
4025:                    try {
4026:                        reconnect();
4027:                        return getUDTs(catalog, schemaPattern, typeNamePattern,
4028:                                types);
4029:                    } catch (DriverSQLException e1) {
4030:                        throw new DriverSQLException(
4031:                                "Connection lost while executing "
4032:                                        + getCurrentMethodName()
4033:                                        + " and automatic reconnect failed ",
4034:                                e1);
4035:                    }
4036:                }
4037:            }
4038:
4039:            /**
4040:             * @see java.sql.DatabaseMetaData#getVersionColumns(java.lang.String,
4041:             *      java.lang.String, java.lang.String)
4042:             */
4043:            protected synchronized ResultSet getVersionColumns(String catalog,
4044:                    String schema, String table) throws DriverSQLException {
4045:                throwSQLExceptionIfClosed();
4046:                try {
4047:                    sendCommand(Commands.DatabaseMetaDataGetVersionColumns);
4048:                    socketOutput.writeLongUTF(catalog);
4049:                    socketOutput.writeLongUTF(schema);
4050:                    socketOutput.writeLongUTF(table);
4051:                    socketOutput.flush();
4052:
4053:                    if (sequoiaUrl.isDebugEnabled())
4054:                        System.out.println(getCurrentMethodName() + "("
4055:                                + catalog + "," + schema + "," + table + ")");
4056:
4057:                    return receiveResultSet(getCurrentMethodName());
4058:                } catch (SerializableException e) {
4059:                    throw new DriverSQLException(e);
4060:                } catch (IOException e) {
4061:                    try {
4062:                        reconnect();
4063:                        return getVersionColumns(catalog, schema, table);
4064:                    } catch (DriverSQLException e1) {
4065:                        throw new DriverSQLException(
4066:                                "Connection lost while executing "
4067:                                        + getCurrentMethodName()
4068:                                        + " and automatic reconnect failed ",
4069:                                e1);
4070:                    }
4071:                }
4072:            }
4073:
4074:            /**
4075:             * Send "FetchNextResultSetRows" command to controller. Throws an SQL
4076:             * exception if controller returns an error; else returns void and lets the
4077:             * caller receive its new rows by itself.
4078:             * 
4079:             * @see org.continuent.sequoia.controller.virtualdatabase.VirtualDatabaseWorkerThread#fetchNextResultSetRows()
4080:             * @param cursorName name of the ResultSet cursor
4081:             * @param fetchSize number of rows to fetch
4082:             * @throws DriverSQLException if an error occurs
4083:             */
4084:            protected synchronized void tryFetchNext(String cursorName,
4085:                    int fetchSize) throws DriverSQLException {
4086:                throwSQLExceptionIfClosed();
4087:                try {
4088:                    sendCommand(Commands.FetchNextResultSetRows);
4089:                    socketOutput.writeLongUTF(cursorName);
4090:                    socketOutput.writeInt(fetchSize);
4091:                    socketOutput.flush();
4092:                    if (sequoiaUrl.isDebugEnabled())
4093:                        System.out.println("Fetching next " + fetchSize
4094:                                + " from " + cursorName);
4095:
4096:                    TypeTag tag = new TypeTag(socketInput);
4097:
4098:                    if (TypeTag.EXCEPTION.equals(tag))
4099:                        throw new DriverSQLException(receiveException());
4100:
4101:                    if (!TypeTag.NOT_EXCEPTION.equals(tag))
4102:                        throw new ProtocolException();
4103:
4104:                    // success, now we can let the DriverResultSet caller receive its data.
4105:
4106:                } catch (IOException e) {
4107:                    throw wrapIOExceptionInDriverSQLException(
4108:                            getCurrentMethodName(), e);
4109:                }
4110:            }
4111:
4112:            /**
4113:             * Gets the caller's method name.
4114:             * 
4115:             * @return method name of the calling function
4116:             */
4117:            static String getCurrentMethodName() {
4118:                return new Throwable().getStackTrace()[1].getMethodName();
4119:            }
4120:
4121:            /**
4122:             * @see java.lang.Object#toString()
4123:             */
4124:            public String toString() {
4125:                // we could use println() instead of LINE_SEPARATOR here
4126:                return "url:"
4127:                        + getUrl()
4128:                        + LINE_SEPARATOR
4129:                        + socket
4130:                        + LINE_SEPARATOR
4131:                        + ((sequoiaUrl != null)
4132:                                && (sequoiaUrl.getParameters() != null) ? "properties:"
4133:                                + sequoiaUrl.getParameters() + LINE_SEPARATOR
4134:                                : "") + "user:" + getUserName()
4135:                        + LINE_SEPARATOR + "connection pooling:"
4136:                        + connectionPooling + LINE_SEPARATOR
4137:                        + "escape backslash:" + escapeBackslash
4138:                        + LINE_SEPARATOR + "escape char:" + escapeChar
4139:                        + LINE_SEPARATOR + "escape single quote:"
4140:                        + escapeSingleQuote + LINE_SEPARATOR;
4141:            }
4142:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.