[teiid-commits] teiid SVN: r3034 - in trunk: build/kits/jboss-container/deploy/teiid and 15 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Mar 25 01:39:34 EDT 2011


Author: shawkins
Date: 2011-03-25 01:39:33 -0400 (Fri, 25 Mar 2011)
New Revision: 3034

Added:
   trunk/build/kits/jboss-container/teiid-docs/licenses/PostgreSQL-BSD.txt
   trunk/client/src/main/java/org/teiid/jdbc/ConnectionProfile.java
   trunk/runtime/src/main/java/org/teiid/transport/pg/
   trunk/runtime/src/main/java/org/teiid/transport/pg/PGbytea.java
   trunk/runtime/src/main/resources/org/teiid/transport/
   trunk/test-integration/common/src/test/java/org/teiid/transport/
   trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
   trunk/test-integration/common/src/test/resources/TestODBCSocketTransport/
   trunk/test-integration/common/src/test/resources/TestODBCSocketTransport/testSelect.expected
Modified:
   trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
   trunk/build/kits/jboss-container/teiid-releasenotes.html
   trunk/client/src/main/java/org/teiid/jdbc/BatchResults.java
   trunk/client/src/main/java/org/teiid/jdbc/ConnectionImpl.java
   trunk/client/src/main/java/org/teiid/jdbc/EmbeddedProfile.java
   trunk/client/src/main/java/org/teiid/jdbc/PreparedStatementImpl.java
   trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java
   trunk/client/src/main/java/org/teiid/jdbc/SocketProfile.java
   trunk/client/src/main/java/org/teiid/jdbc/StatementImpl.java
   trunk/client/src/main/java/org/teiid/jdbc/TeiidDriver.java
   trunk/client/src/test/java/org/teiid/jdbc/TestPreparedStatement.java
   trunk/client/src/test/java/org/teiid/jdbc/TestStatement.java
   trunk/common-core/src/main/java/org/teiid/core/util/StringUtil.java
   trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml
   trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java
   trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
   trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java
   trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java
   trunk/runtime/src/main/java/org/teiid/transport/PGCharsetConverter.java
   trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
   trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java
   trunk/test-integration/common/pom.xml
   trunk/test-integration/common/src/test/java/org/teiid/jdbc/FakeServer.java
Log:
TEIID-1532 TEIID-1531 TEIID-1176 changing the odbc transport to be non-blocking along with various other fixes to charset, preparedstatement handling, and blobs

Modified: trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
===================================================================
--- trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml	2011-03-25 05:39:33 UTC (rev 3034)
@@ -198,10 +198,8 @@
         <property name="bindAddress">${jboss.bind.address}</property>
         <property name="portNumber">35432</property>
         <!-- Max number of threads dedicated to ODBC request processing.
-             Zero indicates the system default of max available processors. (default 15)
-             ODBC queries are currently blocking on IO operations, so this value
-             should be set the expected number of concurrent ODBC queries -->
-        <property name="maxSocketThreads">15</property>
+             Zero indicates the system default of max available processors. (default 0) -->
+        <property name="maxSocketThreads">0</property>
         <!-- SO_RCVBUF size, 0 indicates that system default should be used (default 0) -->
         <property name="inputBufferSize">0</property>
         <!-- SO_SNDBUF size, 0 indicates that system default should be used (default 0) -->

Added: trunk/build/kits/jboss-container/teiid-docs/licenses/PostgreSQL-BSD.txt
===================================================================
--- trunk/build/kits/jboss-container/teiid-docs/licenses/PostgreSQL-BSD.txt	                        (rev 0)
+++ trunk/build/kits/jboss-container/teiid-docs/licenses/PostgreSQL-BSD.txt	2011-03-25 05:39:33 UTC (rev 3034)
@@ -0,0 +1,26 @@
+Copyright (c) 1997-2010, PostgreSQL Global Development Group
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+3. Neither the name of the PostgreSQL Global Development Group nor the names
+   of its contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.


Property changes on: trunk/build/kits/jboss-container/teiid-docs/licenses/PostgreSQL-BSD.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html	2011-03-25 05:39:33 UTC (rev 3034)
@@ -110,7 +110,7 @@
 
 <h4>from 7.3</h4>
 <ul>
-  <LI>SocketConfiguration.maxSocketThreads will interpret a setting of 0 to mean use the system default of max available processors.
+  <LI>SocketConfiguration.maxSocketThreads will interpret a setting of 0 to mean use the system default of max available processors.  Both the ODBC and JDBC transports now default to the 0 setting.
   <LI>maxReserveBatchColumns and maxProcessingBatchesColumns will interpret a setting of -1 to mean auto-calculate acceptable values given the max heap and other information.  See the admin guide for more.
   <LI>The default for org.teiid.useValueCache has changed to false, since typical installations will not greatly benefit from the additional lookup cost.
 </ul>

Modified: trunk/client/src/main/java/org/teiid/jdbc/BatchResults.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/BatchResults.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/BatchResults.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -223,13 +223,13 @@
     }
         
     private void requestBatchAndWait(int beginRow) throws SQLException{
-    	if (batches.size() == savedBatches) {
-        	batches.remove(savedBatches - 1);
-        }
     	setBatch(batchFetcher.requestBatch(beginRow));
 	}
 
-	private void setBatch(Batch batch) {
+	void setBatch(Batch batch) {
+		if (batches.size() == savedBatches) {
+        	batches.remove(savedBatches - 1);
+        }
 		Assertion.assertTrue(batch.getLength() != 0 || batch.isLast());
 		if (batch.getLastRow() != -1) {
             this.lastRowNumber = batch.getLastRow();
@@ -241,11 +241,14 @@
 	}
 
 	public boolean hasNext() throws SQLException {
-		return hasNext(1);
+		return hasNext(1, true);
 	}
 
-	public boolean hasNext(int next) throws SQLException {
+	public Boolean hasNext(int next, boolean wait) throws SQLException {
     	while (this.currentRowNumber + next > highestRowNumber && lastRowNumber == -1) {
+    		if (!wait) {
+    			return null;
+    		}
 			requestNextBatch();
         }
         

Modified: trunk/client/src/main/java/org/teiid/jdbc/ConnectionImpl.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/ConnectionImpl.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/ConnectionImpl.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -41,7 +41,6 @@
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -312,11 +311,9 @@
         // MMConnection.closeStatement() method to be called,
         // which will modify this.statements.  So, we do this iteration
         // in a separate safe copy of the list
-        List statementsSafe = new ArrayList(this.statements);
-        Iterator statementIter = statementsSafe.iterator();
-        SQLException ex = null;
-        while (statementIter.hasNext ()) {
-            Statement statement = (Statement) statementIter.next();
+        List<StatementImpl> statementsSafe = new ArrayList<StatementImpl>(this.statements);
+        SQLException ex = null;
+        for (StatementImpl statement : statementsSafe) {
             try {
             	statement.close();
             } catch (SQLException e) {
@@ -386,7 +383,7 @@
         }
     }
     
-    public Statement createStatement() throws SQLException {
+    public StatementImpl createStatement() throws SQLException {
         return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
     }
 
@@ -397,7 +394,7 @@
      * @param intValue indicating the ResultSet's concurrency
      * @return Statement object.
      */
-    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+    public StatementImpl createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
         //Check to see the connection is open
         checkConnection();
 
@@ -674,6 +671,26 @@
                 }
             }
         }
+    }
+    
+	public ResultsFuture<?> submitSetAutoCommitTrue(boolean commit) throws SQLException {
+    	//Check to see the connection is open
+        checkConnection();
+
+        if (this.autoCommitFlag) {
+            return ResultsFuture.NULL_FUTURE;
+        }
+        
+        this.autoCommitFlag = true;
+    	
+        try {
+	        if (commit) {
+	        	return dqp.commit();
+	        } 
+	        return dqp.rollback();
+        } catch (XATransactionException e) {
+        	throw TeiidSQLException.create(e);
+        }
     }
 
     public void setAutoCommit(boolean autoCommit) throws SQLException {

Added: trunk/client/src/main/java/org/teiid/jdbc/ConnectionProfile.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/ConnectionProfile.java	                        (rev 0)
+++ trunk/client/src/main/java/org/teiid/jdbc/ConnectionProfile.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -0,0 +1,39 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.jdbc;
+
+import java.sql.SQLException;
+import java.util.Properties;
+
+public interface ConnectionProfile {
+
+	/**
+	 * This method tries to make a connection to the given URL. This class
+	 * will return a null if this is not the right driver to connect to the given URL.
+	 * @param The URL used to establish a connection.
+	 * @return Connection object created
+	 * @throws SQLException if it is unable to establish a connection
+	 */
+	ConnectionImpl connect(String url, Properties info) throws TeiidSQLException;
+
+}
\ No newline at end of file


Property changes on: trunk/client/src/main/java/org/teiid/jdbc/ConnectionProfile.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/client/src/main/java/org/teiid/jdbc/EmbeddedProfile.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/EmbeddedProfile.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/EmbeddedProfile.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -22,11 +22,9 @@
 
 package org.teiid.jdbc;
 
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Arrays;
 import java.util.Properties;
-import java.util.logging.Logger;
 
 import org.teiid.core.TeiidException;
 import org.teiid.core.TeiidRuntimeException;
@@ -36,10 +34,8 @@
 import org.teiid.net.ServerConnection;
 
 
-final class EmbeddedProfile {
+final class EmbeddedProfile implements ConnectionProfile {
     
-    private static Logger logger = Logger.getLogger("org.teiid.jdbc"); //$NON-NLS-1$
-    
     /**
      * This method tries to make a connection to the given URL. This class
      * will return a null if this is not the right driver to connect to the given URL.
@@ -47,18 +43,8 @@
      * @return Connection object created
      * @throws SQLException if it is unable to establish a connection
      */
-    public static Connection connect(String url, Properties info) 
-        throws SQLException {
-        ConnectionImpl conn = createConnection(url, info);
-        logger.fine(JDBCPlugin.Util.getString("JDBCDriver.Connection_sucess")); //$NON-NLS-1$ 
-        return conn;
-    }
-    
-    static ConnectionImpl createConnection(String url, Properties info) throws SQLException{
-        
-        // first validate the properties as this may called from the EmbeddedDataSource
-        // and make sure we have all the properties we need.
-        validateProperties(info);
+    public ConnectionImpl connect(String url, Properties info) 
+        throws TeiidSQLException {
         try {
         	ServerConnection sc = (ServerConnection)ReflectionHelper.create("org.teiid.transport.LocalServerConnection", Arrays.asList(info), Thread.currentThread().getContextClassLoader()); //$NON-NLS-1$
 			return new ConnectionImpl(sc, info, url);
@@ -73,21 +59,4 @@
 		}
     }
     
-    /** 
-     * validate some required properties 
-     * @param info the connection properties to be validated
-     * @throws SQLException
-     * @since 4.3
-     */
-    static void validateProperties(Properties info) throws SQLException {
-        // VDB Name has to be there
-        String value = null;
-        value = info.getProperty(BaseDataSource.VDB_NAME);
-        if (value == null || value.trim().length() == 0) {
-            String logMsg = JDBCPlugin.Util.getString("MMDataSource.Virtual_database_name_must_be_specified"); //$NON-NLS-1$
-            throw new SQLException(logMsg);
-        }
-
-    }
-    
 }

Modified: trunk/client/src/main/java/org/teiid/jdbc/PreparedStatementImpl.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/PreparedStatementImpl.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/PreparedStatementImpl.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -55,6 +55,7 @@
 import org.teiid.client.RequestMessage.ResultsMode;
 import org.teiid.client.RequestMessage.StatementType;
 import org.teiid.client.metadata.MetadataResult;
+import org.teiid.client.util.ResultsFuture;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.core.types.BlobImpl;
@@ -189,10 +190,14 @@
     	String msg = JDBCPlugin.Util.getString("JDBC.Method_not_supported"); //$NON-NLS-1$
         throw new TeiidSQLException(msg);
     }
+    
+    public ResultsFuture<Boolean> submitExecute() throws SQLException {
+        return executeSql(new String[] {this.prepareSql}, false, ResultsMode.EITHER, false);
+    }
 
 	@Override
     public boolean execute() throws SQLException {
-        executeSql(new String[] {this.prepareSql}, false, ResultsMode.EITHER);
+        executeSql(new String[] {this.prepareSql}, false, ResultsMode.EITHER, true);
         return hasResultSet();
     }
     
@@ -202,7 +207,7 @@
    	     	return new int[0];
     	}
 	   	try{
-	   		executeSql(new String[] {this.prepareSql}, true, ResultsMode.UPDATECOUNT);
+	   		executeSql(new String[] {this.prepareSql}, true, ResultsMode.UPDATECOUNT, true);
 	   	}finally{
 	   		batchParameterList.clear();
 	   	}
@@ -211,13 +216,13 @@
 
 	@Override
     public ResultSet executeQuery() throws SQLException {
-        executeSql(new String[] {this.prepareSql}, false, ResultsMode.RESULTSET);
+        executeSql(new String[] {this.prepareSql}, false, ResultsMode.RESULTSET, true);
         return resultSet;
     }
 
 	@Override
     public int executeUpdate() throws SQLException {
-        executeSql(new String[] {this.prepareSql}, false, ResultsMode.UPDATECOUNT);
+        executeSql(new String[] {this.prepareSql}, false, ResultsMode.UPDATECOUNT, true);
         return this.updateCounts[0];
     }
     

Modified: trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -227,6 +227,29 @@
     public int getFetchSize() throws SQLException {
         return this.fetchSize;
     }
+    
+    /**
+     * Assumes forward only cursoring
+     */
+    public ResultsFuture<Boolean> submitNext() throws SQLException {
+    	Boolean hasNext = batchResults.hasNext(getOffset() + 1, false);
+    	if (hasNext != null) {
+    		return StatementImpl.booleanFuture(next());
+    	}
+    	ResultsFuture<ResultsMessage> pendingResult = submitRequestBatch(batchResults.getHighestRowNumber() + 1);
+    	final ResultsFuture<Boolean> result = new ResultsFuture<Boolean>();
+    	pendingResult.addCompletionListener(new ResultsFuture.CompletionListener<ResultsMessage>() {
+    		@Override
+    		public void onCompletion(ResultsFuture<ResultsMessage> future) {
+    			try {
+					batchResults.setBatch(processBatch(future.get()));
+				} catch (Throwable t) {
+					result.getResultsReceiver().exceptionOccurred(t);
+				}
+    		}
+		});
+    	return result;
+    }
 
     /**
      * Move row pointer forward one row.  This may cause the cursor
@@ -358,26 +381,11 @@
     }
     
     public Batch requestBatch(int beginRow) throws SQLException{
-    	if (logger.isLoggable(Level.FINER)) {
-    		logger.finer("requestBatch requestID: " + requestID + " beginRow: " + beginRow ); //$NON-NLS-1$ //$NON-NLS-2$
-    	}
     	checkClosed();
         try {
-        	ResultsFuture<ResultsMessage> results = statement.getDQP().processCursorRequest(requestID, beginRow, fetchSize);
-        	int timeoutSeconds = statement.getQueryTimeout();
-        	if (timeoutSeconds == 0) {
-        		timeoutSeconds = Integer.MAX_VALUE;
-        	}
-        	ResultsMessage currentResultMsg = results.get(timeoutSeconds, TimeUnit.SECONDS);
-        	
-            if (currentResultMsg.getException() != null) {
-                throw TeiidSQLException.create(currentResultMsg.getException());
-            }
-
-    		this.accumulateWarnings(currentResultMsg);
-    		return getCurrentBatch(currentResultMsg);
-        } catch (TeiidProcessingException e) {
-			throw TeiidSQLException.create(e);
+        	ResultsFuture<ResultsMessage> results = submitRequestBatch(beginRow);
+        	ResultsMessage currentResultMsg = getResults(results);
+            return processBatch(currentResultMsg);
 		} catch (InterruptedException e) {
 			throw TeiidSQLException.create(e);
 		} catch (ExecutionException e) {
@@ -387,6 +395,41 @@
 		}
     }
 
+	private ResultsFuture<ResultsMessage> submitRequestBatch(int beginRow)
+			throws TeiidSQLException {
+		if (logger.isLoggable(Level.FINER)) {
+			logger.finer("requestBatch requestID: " + requestID + " beginRow: " + beginRow ); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		ResultsFuture<ResultsMessage> results;
+		try {
+			results = statement.getDQP().processCursorRequest(requestID, beginRow, fetchSize);
+		} catch (TeiidProcessingException e) {
+			throw TeiidSQLException.create(e);
+		}
+		return results;
+	}
+
+	private Batch processBatch(
+			ResultsMessage currentResultMsg) throws TeiidSQLException {
+		if (currentResultMsg.getException() != null) {
+		    throw TeiidSQLException.create(currentResultMsg.getException());
+		}
+
+		this.accumulateWarnings(currentResultMsg);
+		return getCurrentBatch(currentResultMsg);
+	}
+
+	private ResultsMessage getResults(ResultsFuture<ResultsMessage> results)
+			throws SQLException, InterruptedException, ExecutionException,
+			TimeoutException {
+		int timeoutSeconds = statement.getQueryTimeout();
+		if (timeoutSeconds == 0) {
+			timeoutSeconds = Integer.MAX_VALUE;
+		}
+		ResultsMessage currentResultMsg = results.get(timeoutSeconds, TimeUnit.SECONDS);
+		return currentResultMsg;
+	}
+
 	private Batch getCurrentBatch(ResultsMessage currentResultMsg) {
 		this.updatedPlanDescription = currentResultMsg.getPlanDescription();
 		boolean isLast = currentResultMsg.getResults().length == 0 || currentResultMsg.getFinalRow() == currentResultMsg.getLastRow();
@@ -400,7 +443,7 @@
 	}
 
 	protected boolean hasNext() throws SQLException {
-		return batchResults.hasNext(getOffset() + 1);
+		return batchResults.hasNext(getOffset() + 1, true);
 	}
 	
 	protected int getOffset() {

Modified: trunk/client/src/main/java/org/teiid/jdbc/SocketProfile.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/SocketProfile.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/SocketProfile.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -22,31 +22,24 @@
 
 package org.teiid.jdbc;
 
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 import org.teiid.core.TeiidException;
-import org.teiid.net.CommunicationException;
-import org.teiid.net.ConnectionException;
 import org.teiid.net.ServerConnection;
 import org.teiid.net.socket.SocketServerConnectionFactory;
 
 
 /**
- * <p> The java.sql.DriverManager class uses this class to connect to Teiid Server or Teiid Embedded.
+ * <p> The java.sql.DriverManager class uses this class to connect to Teiid Server.
  * The TeiidDriver class has a static initializer, which
  * is used to instantiate and register itself with java.sql.DriverManager. The
  * DriverManager's <code>getConnection</code> method calls <code>connect</code>
  * method on available registered drivers. </p>
  */
 
-final class SocketProfile {
+final class SocketProfile implements ConnectionProfile {
 	
-	private static Logger logger = Logger.getLogger("org.teiid.jdbc"); //$NON-NLS-1$
-    
     /**
      * This method tries to make a connection to the given URL. This class
      * will return a null if this is not the right driver to connect to the given URL.
@@ -54,29 +47,15 @@
      * @return Connection object created
      * @throws SQLException if it is unable to establish a connection to the server.
      */
-    static Connection connect(String url, Properties info) throws SQLException {
+    public ConnectionImpl connect(String url, Properties info) throws TeiidSQLException {
 
-        ConnectionImpl myConnection = null;
+        ServerConnection serverConn;
+		try {
+			serverConn = SocketServerConnectionFactory.getInstance().getConnection(info);
+		} catch (TeiidException e) {
+			throw TeiidSQLException.create(e);
+		}
 
-        try {
-            myConnection = createConnection(url, info);
-        } catch (TeiidException e) {
-            logger.log(Level.SEVERE, "Could not create connection", e); //$NON-NLS-1$
-            throw TeiidSQLException.create(e, e.getMessage());
-        }
-
-        // logging
-        String logMsg = JDBCPlugin.Util.getString("JDBCDriver.Connection_sucess"); //$NON-NLS-1$
-        logger.fine(logMsg);
-
-        return myConnection;
-    }
-
-    static ConnectionImpl createConnection(String url, Properties info)
-        throws ConnectionException, CommunicationException {
-
-        ServerConnection serverConn = SocketServerConnectionFactory.getInstance().getConnection(info);
-
         // construct a MMConnection object.
         ConnectionImpl connection = new ConnectionImpl(serverConn, info, url);
         return connection;

Modified: trunk/client/src/main/java/org/teiid/jdbc/StatementImpl.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/StatementImpl.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/StatementImpl.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -39,7 +39,6 @@
 import java.util.Properties;
 import java.util.TimeZone;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.logging.Level;
@@ -57,6 +56,7 @@
 import org.teiid.client.metadata.ResultsMetadataDefaults;
 import org.teiid.client.plan.Annotation;
 import org.teiid.client.plan.PlanNode;
+import org.teiid.client.util.ResultsFuture;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidException;
 import org.teiid.core.TeiidProcessingException;
@@ -117,7 +117,7 @@
     private Collection<Annotation> annotations;
 
     // resultSet object produced by execute methods on the statement.
-    protected ResultSetImpl resultSet;
+    protected volatile ResultSetImpl resultSet;
 
     private List<Exception> serverWarnings;
 
@@ -303,10 +303,14 @@
             throw new TeiidSQLException(JDBCPlugin.Util.getString("MMStatement.Stmt_closed")); //$NON-NLS-1$
         }
     }
+    
+    public ResultsFuture<Boolean> submitExecute(String sql) throws SQLException {
+    	return executeSql(new String[] {sql}, false, ResultsMode.EITHER, false);
+    }
 
 	@Override
     public boolean execute(String sql) throws SQLException {
-        executeSql(new String[] {sql}, false, ResultsMode.EITHER);
+        executeSql(new String[] {sql}, false, ResultsMode.EITHER, true);
         return hasResultSet();
     }
     
@@ -316,20 +320,20 @@
             return new int[0];
         }
         String[] commands = (String[])batchedUpdates.toArray(new String[batchedUpdates.size()]);
-        executeSql(commands, true, ResultsMode.UPDATECOUNT);
+        executeSql(commands, true, ResultsMode.UPDATECOUNT, true);
         return updateCounts;
     }
 
 	@Override
     public ResultSet executeQuery(String sql) throws SQLException {
-        executeSql(new String[] {sql}, false, ResultsMode.RESULTSET);
+        executeSql(new String[] {sql}, false, ResultsMode.RESULTSET, true);
         return resultSet;
     }
 
 	@Override
     public int executeUpdate(String sql) throws SQLException {
         String[] commands = new String[] {sql};
-        executeSql(commands, false, ResultsMode.UPDATECOUNT);
+        executeSql(commands, false, ResultsMode.UPDATECOUNT, true);
         return this.updateCounts[0];
     }
 
@@ -384,7 +388,8 @@
 		resultSet.setMaxFieldSize(this.maxFieldSize);
 	}
     
-    protected void executeSql(String[] commands, boolean isBatchedCommand, ResultsMode resultsMode)
+	@SuppressWarnings("unchecked")
+	protected ResultsFuture<Boolean> executeSql(String[] commands, boolean isBatchedCommand, ResultsMode resultsMode, boolean synch)
         throws SQLException {
         checkStatement();
         resetExecutionState();
@@ -405,7 +410,7 @@
         			JDBCURL.addNormalizedProperty(key, value, this.driverConnection.getExecutionProperties());
         		}
         		this.updateCounts = new int[] {0};
-        		return;
+        		return booleanFuture(true);
         	}
         	match = TRANSACTION_STATEMENT.matcher(commands[0]);
         	if (match.matches()) {
@@ -414,15 +419,38 @@
         			throw new TeiidSQLException(JDBCPlugin.Util.getString("StatementImpl.set_result_set")); //$NON-NLS-1$
         		}
         		String command = match.group(1);
+        		Boolean commit = null;
         		if (StringUtil.startsWithIgnoreCase(command, "start")) { //$NON-NLS-1$
         			this.getConnection().setAutoCommit(false);
         		} else if (command.equalsIgnoreCase("commit")) { //$NON-NLS-1$
-        			this.getConnection().setAutoCommit(true);
+        			commit = true;
+        			if (synch) {
+        				this.getConnection().setAutoCommit(true);
+        			}
         		} else if (command.equalsIgnoreCase("rollback")) { //$NON-NLS-1$
-        			this.getConnection().rollback(false);
+        			commit = false;
+        			if (synch) {
+        				this.getConnection().rollback(false);
+        			}
         		}
         		this.updateCounts = new int[] {0};
-        		return;
+        		if (commit != null && !synch) {
+        			ResultsFuture<?> pending = this.getConnection().submitSetAutoCommitTrue(commit);
+        			final ResultsFuture<Boolean> result = new ResultsFuture<Boolean>();
+        			pending.addCompletionListener(new ResultsFuture.CompletionListener() {
+        				@Override
+        				public void onCompletion(ResultsFuture future) {
+        					try {
+								future.get();
+								result.getResultsReceiver().receiveResults(false);
+							} catch (Throwable t) {
+								result.getResultsReceiver().exceptionOccurred(t);
+							}
+        				}
+					});
+        			return result;
+        		}
+        		return booleanFuture(false);
         	}
         	match = SHOW_STATEMENT.matcher(commands[0]);
         	if (match.matches()) {
@@ -443,7 +471,7 @@
         			}
         			createResultSet(records, new String[] {"PLAN_TEXT", "PLAN_XML", "DEBUG_LOG"}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
         					new String[] {JDBCSQLTypeInfo.CLOB, JDBCSQLTypeInfo.XML, JDBCSQLTypeInfo.CLOB});
-            		return;
+        			return booleanFuture(true);
         		}
         		if (show.equalsIgnoreCase("ANNOTATIONS")) { //$NON-NLS-1$
         			List<ArrayList<Object>> records = new ArrayList<ArrayList<Object>>(1);
@@ -458,7 +486,7 @@
         			}
         			createResultSet(records, new String[] {"CATEGORY", "PRIORITY", "ANNOTATION", "RESOLUTION"}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
         					new String[] {JDBCSQLTypeInfo.STRING, JDBCSQLTypeInfo.STRING, JDBCSQLTypeInfo.STRING, JDBCSQLTypeInfo.STRING});
-            		return;
+        			return booleanFuture(true);
         		}
         		if (show.equalsIgnoreCase("ALL")) { //$NON-NLS-1$
         			List<ArrayList<Object>> records = new ArrayList<ArrayList<Object>>(1);
@@ -470,25 +498,85 @@
         			}
         			createResultSet(records, new String[] {"NAME", "VALUE"}, //$NON-NLS-1$ //$NON-NLS-2$
         					new String[] {JDBCSQLTypeInfo.STRING, JDBCSQLTypeInfo.STRING});
-            		return;
+        			return booleanFuture(true);
         		}
         		List<List<String>> records = Collections.singletonList(Collections.singletonList(driverConnection.getExecutionProperties().getProperty(JDBCURL.getValidKey(show))));
     			createResultSet(records, new String[] {show}, new String[] {JDBCSQLTypeInfo.STRING});
-        		return;
+        		return booleanFuture(true);
         	}
         }
         
-        RequestMessage reqMessage = createRequestMessage(commands, isBatchedCommand, resultsMode);
-    	ResultsMessage resultsMsg = null;
-        try {
-        	resultsMsg = sendRequestMessageAndWait(reqMessage);
+        final RequestMessage reqMessage = createRequestMessage(commands, isBatchedCommand, resultsMode);
+    	ResultsFuture<ResultsMessage> pendingResult = this.sendRequestMessage(reqMessage);
+    	
+    	if (synch) {
+	    	ResultsMessage resultsMsg = getResults(reqMessage, pendingResult);
+	        postReceiveResults(reqMessage, resultsMsg);
+	        return booleanFuture(hasResultSet());
+    	}
+    	
+    	final ResultsFuture<Boolean> result = new ResultsFuture<Boolean>();
+    	pendingResult.addCompletionListener(new ResultsFuture.CompletionListener<ResultsMessage>() {
+    		@Override
+    		public void onCompletion(ResultsFuture<ResultsMessage> future) {
+    			try {
+					postReceiveResults(reqMessage, future.get());
+					result.getResultsReceiver().receiveResults(hasResultSet());
+				} catch (Throwable t) {
+					result.getResultsReceiver().exceptionOccurred(t);
+				}
+    		}
+		});
+    	return result;
+    }
+
+	public static ResultsFuture<Boolean> booleanFuture(boolean isTrue) {
+		ResultsFuture<Boolean> rs = new ResultsFuture<Boolean>();
+		rs.getResultsReceiver().receiveResults(isTrue);
+		return rs;
+	}
+
+	private ResultsMessage getResults(RequestMessage reqMessage,
+			ResultsFuture<ResultsMessage> pendingResult)
+			throws TeiidSQLException {
+		try {
+    		long timeoutMillis = queryTimeout * 1000;
+            long endTime = System.currentTimeMillis() + timeoutMillis;
+            ResultsMessage result = null;        
+            while (result == null) {
+
+            	if (timeoutMillis > 0 && endTime <= System.currentTimeMillis() && commandStatus != TIMED_OUT && commandStatus != CANCELLED) {
+    	            timeoutOccurred();
+            	}
+            	
+                checkStatement();
+    			try {
+    				result = pendingResult.get(SPIN_TIMEOUT, TimeUnit.MILLISECONDS);
+    			} catch (ExecutionException e) {
+    				throw TeiidSQLException.create(e);
+    			} catch (TimeoutException e) {
+    				continue;
+    			}
+            }
+            
+        	if (commandStatus == CANCELLED) {
+                throw new TeiidSQLException(JDBCPlugin.Util.getString("MMStatement.Cancel_before_execute")); //$NON-NLS-1$
+            }
+        	 
+        	if (commandStatus == TIMED_OUT) {
+                throw new TeiidSQLException(JDBCPlugin.Util.getString("MMStatement.Timeout_before_complete")); //$NON-NLS-1$
+            }    	
+            return result;
         } catch ( Throwable ex ) {
         	String msg = JDBCPlugin.Util.getString("MMStatement.Error_executing_stmt", reqMessage.getCommandString()); //$NON-NLS-1$ 
             logger.log(ex instanceof SQLException?Level.WARNING:Level.SEVERE, msg, ex);
             throw TeiidSQLException.create(ex, msg);
         }
-        
-        // warnings thrown
+	}
+
+	private void postReceiveResults(RequestMessage reqMessage,
+			ResultsMessage resultsMsg) throws TeiidSQLException, SQLException {
+		// warnings thrown
         List resultsWarning = resultsMsg.getWarnings();
 
         setAnalysisInfo(resultsMsg);
@@ -524,7 +612,7 @@
         }
         
         logger.fine(JDBCPlugin.Util.getString("MMStatement.Success_query", reqMessage.getCommandString())); //$NON-NLS-1$
-    }
+	}
 
 	protected RequestMessage createRequestMessage(String[] commands,
 			boolean isBatchedCommand, ResultsMode resultsMode) {
@@ -648,7 +736,7 @@
      * @return ResultSet object giving the next available ResultSet
      * @throws SQLException should never occur
      */
-    public ResultSet getResultSet() throws SQLException {
+    public ResultSetImpl getResultSet() throws SQLException {
         //Check to see the statement is closed and throw an exception
         checkStatement();
         if (!hasResultSet()) {
@@ -887,8 +975,8 @@
     /**
      * Send out request message with necessary states.
      */
-    protected ResultsMessage sendRequestMessageAndWait(RequestMessage reqMsg)
-        throws SQLException, InterruptedException {
+    protected ResultsFuture<ResultsMessage> sendRequestMessage(RequestMessage reqMsg)
+        throws SQLException {
         this.currentRequestID = this.driverConnection.nextRequestID();
         // Create a request message
         reqMsg.setExecutionPayload(this.payload);        
@@ -902,39 +990,11 @@
 
         reqMsg.setExecutionId(this.currentRequestID);
     	
-        Future<ResultsMessage> pendingResult = null;
 		try {
-			pendingResult = this.getDQP().executeRequest(this.currentRequestID, reqMsg);
+			return this.getDQP().executeRequest(this.currentRequestID, reqMsg);
 		} catch (TeiidException e) {
 			throw TeiidSQLException.create(e);
 		}
-		long timeoutMillis = queryTimeout * 1000;
-        long endTime = System.currentTimeMillis() + timeoutMillis;
-        ResultsMessage result = null;        
-        while (result == null) {
-
-        	if (timeoutMillis > 0 && endTime <= System.currentTimeMillis() && commandStatus != TIMED_OUT && commandStatus != CANCELLED) {
-	            timeoutOccurred();
-        	}
-        	
-            checkStatement();
-			try {
-				result = pendingResult.get(SPIN_TIMEOUT, TimeUnit.MILLISECONDS);
-			} catch (ExecutionException e) {
-				throw TeiidSQLException.create(e);
-			} catch (TimeoutException e) {
-				continue;
-			}
-        }
-        
-    	if (commandStatus == CANCELLED) {
-            throw new TeiidSQLException(JDBCPlugin.Util.getString("MMStatement.Cancel_before_execute")); //$NON-NLS-1$
-        }
-    	 
-    	if (commandStatus == TIMED_OUT) {
-            throw new TeiidSQLException(JDBCPlugin.Util.getString("MMStatement.Timeout_before_complete")); //$NON-NLS-1$
-        }    	
-    	return result;
     }
 
     long getCurrentRequestID() {

Modified: trunk/client/src/main/java/org/teiid/jdbc/TeiidDriver.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/TeiidDriver.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/main/java/org/teiid/jdbc/TeiidDriver.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -69,6 +69,9 @@
             logger.log(Level.SEVERE, logMsg);
         }
     }
+    
+    private static SocketProfile SOCKET_PROFILE = new SocketProfile();
+    private ConnectionProfile embeddedProfile = new EmbeddedProfile();
 
     public static TeiidDriver getInstance() {
         return INSTANCE;
@@ -94,12 +97,31 @@
             info = PropertiesUtils.clone(info);
         }
         parseURL(url, info);
-    	if (conn == ConnectionType.Embedded) {
-    		return EmbeddedProfile.connect(url, info);
-    	}
-		return SocketProfile.connect(url, info);
+        
+        ConnectionImpl myConnection = null;
+
+        try {
+        	if (conn == ConnectionType.Embedded) {
+        		myConnection = embeddedProfile.connect(url, info);
+        	} else { 
+        		myConnection = SOCKET_PROFILE.connect(url, info);
+        	}
+        } catch (TeiidSQLException e) {
+            logger.log(Level.SEVERE, "Could not create connection", e); //$NON-NLS-1$
+            throw TeiidSQLException.create(e, e.getMessage());
+        }
+
+        // logging
+        String logMsg = JDBCPlugin.Util.getString("JDBCDriver.Connection_sucess"); //$NON-NLS-1$
+        logger.fine(logMsg);
+        
+		return myConnection;
     }
     
+    public void setEmbeddedProfile(ConnectionProfile embeddedProfile) {
+		this.embeddedProfile = embeddedProfile;
+	}
+    
     /**
      * Returns true if the driver thinks that it can open a connection to the given URL.
      * Expected URL format for server mode is

Modified: trunk/client/src/test/java/org/teiid/jdbc/TestPreparedStatement.java
===================================================================
--- trunk/client/src/test/java/org/teiid/jdbc/TestPreparedStatement.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/test/java/org/teiid/jdbc/TestPreparedStatement.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -42,9 +42,6 @@
 import org.teiid.client.RequestMessage.ResultsMode;
 import org.teiid.client.security.LogonResult;
 import org.teiid.client.util.ResultsFuture;
-import org.teiid.jdbc.ConnectionImpl;
-import org.teiid.jdbc.PreparedStatementImpl;
-import org.teiid.jdbc.TeiidSQLException;
 import org.teiid.net.ServerConnection;
 
 
@@ -55,17 +52,6 @@
 public class TestPreparedStatement {
 
 	/**
-	 * Test that <code>MMPreparedStatement</code>'s <code>execute()</code> method
-	 * will throw a <code>MMSQLException</code> if a connection does not exist.
-	 * 
-	 * @throws Exception
-	 */
-	@Test(expected=TeiidSQLException.class) public void testUpdateException() throws Exception {
-		PreparedStatementImpl statement = getMMPreparedStatement("delete from table"); //$NON-NLS-1$
-		statement.execute();
-	}
-	
-	/**
 	 * Verify that the <code>executeBatch()</code> method of <code>
 	 * MMPreparedStatement</code> is resulting in the correct command, 
 	 * parameter values for each command of the batch, and the request type 

Modified: trunk/client/src/test/java/org/teiid/jdbc/TestStatement.java
===================================================================
--- trunk/client/src/test/java/org/teiid/jdbc/TestStatement.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/client/src/test/java/org/teiid/jdbc/TestStatement.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -35,18 +35,10 @@
 import org.teiid.client.RequestMessage;
 import org.teiid.client.ResultsMessage;
 import org.teiid.client.util.ResultsFuture;
-import org.teiid.jdbc.ConnectionImpl;
-import org.teiid.jdbc.TeiidSQLException;
-import org.teiid.jdbc.StatementImpl;
 
 
 public class TestStatement {
 
-	@Test(expected=TeiidSQLException.class) public void testUpdateException() throws Exception {
-		StatementImpl statement = new StatementImpl(Mockito.mock(ConnectionImpl.class), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
-		statement.executeQuery("delete from table"); //$NON-NLS-1$
-	}
-	
 	@Test public void testBatchExecution() throws Exception {
 		ConnectionImpl conn = Mockito.mock(ConnectionImpl.class);
 		DQP dqp = Mockito.mock(DQP.class);
@@ -97,5 +89,21 @@
 		assertFalse(statement.execute("rollback")); //$NON-NLS-1$
 		Mockito.verify(conn).rollback(false);
 	}
+
+	@SuppressWarnings("unchecked")
+	@Test public void testTransactionStatementsAsynch() throws Exception {
+		ConnectionImpl conn = Mockito.mock(ConnectionImpl.class);
+		Mockito.stub(conn.submitSetAutoCommitTrue(Mockito.anyBoolean())).toReturn((ResultsFuture)ResultsFuture.NULL_FUTURE);
+		Properties p = new Properties();
+		Mockito.stub(conn.getExecutionProperties()).toReturn(p);
+		StatementImpl statement = new StatementImpl(conn, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+		statement.submitExecute("start transaction"); //$NON-NLS-1$
+		Mockito.verify(conn).setAutoCommit(false);
+		statement.submitExecute("commit"); //$NON-NLS-1$
+		Mockito.verify(conn).submitSetAutoCommitTrue(true);
+		statement.submitExecute("start transaction"); //$NON-NLS-1$
+		statement.submitExecute("rollback"); //$NON-NLS-1$
+		Mockito.verify(conn).submitSetAutoCommitTrue(false);
+	}
 	
 }

Modified: trunk/common-core/src/main/java/org/teiid/core/util/StringUtil.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/util/StringUtil.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/common-core/src/main/java/org/teiid/core/util/StringUtil.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -295,26 +295,20 @@
 	 * replaced with the replace string
 	 */
 	public static String replaceAll(String source, String search, String replace) {
-	    if (source != null && search != null && search.length() > 0 && replace != null) {
-	        int start = source.indexOf(search);
-	        if (start > -1) {
-		        StringBuffer newString = new StringBuffer(source);
-	            replaceAll(newString, search, replace);
-		        return newString.toString();
-	        }
+	    if (source == null || search == null || search.length() == 0 || replace == null) {
+	    	return source;
 	    }
-	    return source;    
-	}
-
-    public static void replaceAll(StringBuffer source, String search, String replace) {
-	    if (source != null && search != null && search.length() > 0 && replace != null) {
-	        int start = source.toString().indexOf(search);
+        int start = source.indexOf(search);
+        if (start > -1) {
+	        StringBuffer newString = new StringBuffer(source);
 	        while (start > -1) {
 	            int end = start + search.length();
-                source.replace(start, end, replace);
-	            start = source.toString().indexOf(search, start + replace.length());
+	            newString.replace(start, end, replace);
+	            start = newString.indexOf(search, start + replace.length());
 	        }
-	    }
+	        return newString.toString();
+        }
+	    return source;    
 	}
 
     /**

Modified: trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml
===================================================================
--- trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml	2011-03-25 05:39:33 UTC (rev 3034)
@@ -109,15 +109,10 @@
 			The default input output buffer sizes are set to 0, which will use the system default.  
 			Before adjusting this value keep in mind that each JDBC, ODBC, and Admin client will create a new socket connection.  
 			Setting these values to a large buffer size should only be done if the number of client is constrained.
-			All JDBC socket operations are non-blocking, so setting the number of maxThreads
+			All JDBC/ODBC socket operations are non-blocking, so setting the number of maxThreads
 			higher than the maximum effective parallelism of the machine should not result in greater performance.  
 			The default value 0 for JDBC socket threads will set the max to the number of available processors.
 			</para>
-			<para>  
-			At this time, ODBC queries are executed synchronously from the socket thread.
-			Simultaneous long-running queries may exhaust the available threads.
-			Consider increasing the default max threads (15) for ODBC if you
-			expect a higher concurrent load of long-running ODBC client queries.</para>
 	</section>
 	<section>
 		<title>LOBs</title>

Modified: trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -21,17 +21,17 @@
  */
 package org.teiid.odbc;
 
-import java.nio.charset.Charset;
 import java.sql.ParameterMetaData;
-import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.util.Properties;
 
+import org.teiid.jdbc.ResultSetImpl;
+
 public interface ODBCClientRemote {
 	
 	void initialized(Properties props);
 	
-	void setEncoding(Charset value);
+	void setEncoding(String value);
 	
 	//	AuthenticationCleartextPassword (B)
 	void useClearTextAuthentication();
@@ -64,7 +64,7 @@
 	
 	//	DataRow (B)
 	//	CommandComplete (B)
-	void sendResults(String sql, ResultSet rs, boolean describeRows);
+	void sendResults(String sql, ResultSetImpl rs, boolean describeRows);
 
 	//	CommandComplete (B)
 	void sendUpdateCount(String sql, int updateCount);

Modified: trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -23,10 +23,8 @@
 
 import java.io.IOException;
 import java.io.StringReader;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.Statement;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -34,14 +32,17 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.teiid.client.util.ResultsFuture;
 import org.teiid.core.util.ApplicationInfo;
 import org.teiid.core.util.StringUtil;
 import org.teiid.jdbc.ConnectionImpl;
+import org.teiid.jdbc.PreparedStatementImpl;
+import org.teiid.jdbc.StatementImpl;
 import org.teiid.jdbc.TeiidDriver;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
 import org.teiid.runtime.RuntimePlugin;
-import org.teiid.transport.PGCharsetConverter;
+import org.teiid.transport.ODBCClientInstance;
 
 /**
  * While executing the multiple prepared statements I see this bug currently
@@ -139,17 +140,23 @@
 	private static Pattern savepointPattern = Pattern.compile("SAVEPOINT (\\w+\\d+_*)"); //$NON-NLS-1$
 	private static Pattern rollbackPattern = Pattern.compile("ROLLBACK\\s*(to)*\\s*(\\w+\\d+_*)*"); //$NON-NLS-1$
 	
+	private TeiidDriver driver;
+	private ODBCClientInstance clientInstance;
 	private ODBCClientRemote client;
 	private Properties props;
 	private AuthenticationType authType;
 	private ConnectionImpl connection;
 	
+	private volatile ResultsFuture<Boolean> executionFuture;
+	
 	// TODO: this is unbounded map; need to define some boundaries as to how many stmts each session can have
 	private Map<String, Prepared> preparedMap = Collections.synchronizedMap(new HashMap<String, Prepared>());
 	private Map<String, Portal> portalMap = Collections.synchronizedMap(new HashMap<String, Portal>());
 	
-	public ODBCServerRemoteImpl(ODBCClientRemote client, AuthenticationType authType) {
-		this.client = client;
+	public ODBCServerRemoteImpl(ODBCClientInstance client, AuthenticationType authType, TeiidDriver driver) {
+		this.driver = driver;
+		this.client = client.getClient();
+		this.clientInstance = client;
 		this.authType = authType;
 	}
 	
@@ -172,7 +179,6 @@
 		try {
 			 java.util.Properties info = new java.util.Properties();
 			String url = "jdbc:teiid:"+databaseName+";ApplicationName=ODBC"; //$NON-NLS-1$ //$NON-NLS-2$
-			TeiidDriver driver = new TeiidDriver();
 			info.put("user", user); //$NON-NLS-1$
 			info.put("password", password); //$NON-NLS-1$
 			this.connection =  (ConnectionImpl)driver.connect(url, info);
@@ -194,7 +200,8 @@
 			}
 						
 			if (sql != null) {
-				String modfiedSQL = sql.replaceAll("\\$\\d+", "?");//$NON-NLS-1$ //$NON-NLS-2$
+				String modfiedSQL = fixSQL(sql);
+				modfiedSQL = modfiedSQL.replaceAll("\\$\\d+", "?");//$NON-NLS-1$ //$NON-NLS-2$
 				try {
 					// close if the name is already used or the unnamed prepare; otherwise
 					// stmt is alive until session ends.
@@ -203,7 +210,7 @@
 						previous.stmt.close();
 					}
 					
-					PreparedStatement stmt = this.connection.prepareStatement(modfiedSQL);
+					PreparedStatementImpl stmt = this.connection.prepareStatement(modfiedSQL);
 					this.preparedMap.put(prepareName, new Prepared(prepareName, sql, stmt, paramType));
 					this.client.prepareCompleted(prepareName);
 				} catch (SQLException e) {
@@ -256,11 +263,14 @@
 
 	@Override
 	public void execute(String bindName, int maxRows) {
+		if (isAwaitingAsynch()) {
+			return;
+		}
 		if (bindName == null || bindName.length() == 0) {
 			bindName  = UNNAMED;
 		}		
 		
-		Portal query = this.portalMap.get(bindName);
+		final Portal query = this.portalMap.get(bindName);
 		if (query == null) {
 			this.client.errorOccurred(RuntimePlugin.Util.getString("not_bound", bindName)); //$NON-NLS-1$
 			sync();
@@ -271,24 +281,33 @@
 				return;
 			}
 			
-            PreparedStatement stmt = query.stmt;
+            final PreparedStatementImpl stmt = query.stmt;
             try {
             	// maxRows = 0, means unlimited.
             	if (maxRows != 0) {
             		stmt.setMaxRows(maxRows);
             	}
             	
-                boolean result = stmt.execute();
-                if (result) {
-                    try {
-                        ResultSet rs = stmt.getResultSet();
-                        this.client.sendResults(query.sql, rs, true);
-                    } catch (SQLException e) {
-                        this.client.errorOccurred(e);
-                    }
-                } else {
-                	this.client.sendUpdateCount(query.sql, stmt.getUpdateCount());
-                }
+                this.executionFuture = stmt.submitExecute();
+                executionFuture.addCompletionListener(new ResultsFuture.CompletionListener<Boolean>() {
+	        		@Override
+	        		public void onCompletion(ResultsFuture<Boolean> future) {
+	        			executionFuture = null;
+                        try {
+		        			if (future.get()) {
+	                            client.sendResults(query.sql, stmt.getResultSet(), true);
+		                    } else {
+		                    	client.sendUpdateCount(query.sql, stmt.getUpdateCount());
+		                    	setEncoding();
+		                    }
+                        } catch (Throwable e) {
+                            client.errorOccurred(e);
+                        }
+                        if (!clientInstance.hasPending()) {
+                        	sync();
+                        }
+	        		}
+				});
             } catch (SQLException e) {
             	this.client.errorOccurred(e);
             }			
@@ -344,6 +363,7 @@
 					modified = "SELECT current_database()"; //$NON-NLS-1$
 				}
 				else {
+					//these are somewhat dangerous
 					modified = modified.replaceAll("E'", "'"); //$NON-NLS-1$ //$NON-NLS-2$
 					modified =  modified.replaceAll("::[A-Za-z0-9]*", " "); //$NON-NLS-1$ //$NON-NLS-2$
 					modified =  modified.replaceAll("'pg_toast'", "'SYS'"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -362,37 +382,13 @@
 			else {
 				Matcher m = setPattern.matcher(sql);
 				if (m.matches()) {
-					if (m.group(2).equalsIgnoreCase("client_encoding")) { //$NON-NLS-1$
-						this.client.setEncoding(PGCharsetConverter.getCharset(m.group(4)));
-					}
-					else {
-						this.props.setProperty(m.group(2), m.group(4));
-					}
-					modified = "SELECT 'SET'"; //$NON-NLS-1$
+					modified = "SET " + m.group(2) + " " + m.group(4); //$NON-NLS-1$ //$NON-NLS-2$
 				}
 				else if (modified.equalsIgnoreCase("BEGIN")) { //$NON-NLS-1$
-					try {
-						this.connection.setAutoCommit(false);
-						modified = "SELECT 'BEGIN'"; //$NON-NLS-1$
-					} catch (SQLException e) {
-						this.client.errorOccurred(e);
-					}
+					modified = "START TRANSACTION"; //$NON-NLS-1$
 				}
-				else if (modified.equalsIgnoreCase("COMMIT")) { //$NON-NLS-1$
-					try {
-						this.connection.setAutoCommit(true);
-						modified = "SELECT 'COMMIT'"; //$NON-NLS-1$
-					} catch (SQLException e) {
-						this.client.errorOccurred(e);
-					}					
-				}
 				else if ((m = rollbackPattern.matcher(modified)).matches()) {
-					try {
-						this.connection.rollback(false);
-						modified = "SELECT 'ROLLBACK'"; //$NON-NLS-1$
-					} catch (SQLException e) {
-						this.client.errorOccurred(e);
-					}					
+					modified = "ROLLBACK"; //$NON-NLS-1$
 				}	
 				else if ((m = savepointPattern.matcher(modified)).matches()) {
 					modified = "SELECT 'SAVEPOINT'"; //$NON-NLS-1$
@@ -413,8 +409,10 @@
 	}
 
 	@Override
-	public void executeQuery(String query) {
-
+	public void executeQuery(final String query) {
+		if (isAwaitingAsynch()) {
+			return;
+		}
 		//46.2.3 Note that a simple Query message also destroys the unnamed portal.
 		this.portalMap.remove(UNNAMED);
 		this.preparedMap.remove(UNNAMED);
@@ -424,39 +422,20 @@
     		sync();
     		return;
     	}
-		
-		try {			
-	        ScriptReader reader = new ScriptReader(new StringReader(query));
-	        String s = fixSQL(reader.readStatement());
-	        while (s != null) {
-	            Statement stmt = null;
-	            try {
-	                stmt = this.connection.createStatement();
-	                boolean result = stmt.execute(s);
-	                if (result) {
-	                	this.client.sendResults(s, stmt.getResultSet(), true);
-	                } else {
-	                	this.client.sendUpdateCount(s, stmt.getUpdateCount());
-	                }
-	                s = fixSQL(reader.readStatement());
-	            } catch (SQLException e) {
-	                this.client.errorOccurred(e);
-	                break;
-	            } finally {
-	                try {
-	                	if (stmt != null) {
-	                		stmt.close();
-	                	}
-					} catch (SQLException e) {
-						this.client.errorOccurred(e);
-						break;
-					}
-	            }
-	        }
-		} catch(IOException e) {
-			this.client.errorOccurred(e);
+        QueryWorkItem r = new QueryWorkItem(query);
+		r.run();
+	}
+
+	/**
+	 * Just a sanity check.  Should never happen
+	 */
+	private boolean isAwaitingAsynch() {
+		if (this.executionFuture != null) {
+			this.client.errorOccurred("Awaiting asynch result"); //$NON-NLS-1$
+			sync();
+			return true;
 		}
-		sync();
+		return false;
 	}
 
 	@Override
@@ -498,6 +477,9 @@
 
 	@Override
 	public void sync() {
+		if (this.executionFuture != null) {
+			return;
+		}
 		boolean inTxn = false;
 		boolean failedTxn = false;
 		try {
@@ -608,12 +590,85 @@
 		this.client.sslDenied();
 	}
 	
-    /**
+	private void setEncoding() {
+		try {
+			StatementImpl t = connection.createStatement();
+			ResultSet rs = t.executeQuery("show client_encoding"); //$NON-NLS-1$
+			if (rs.next()) {
+				String encoding = rs.getString(1);
+				if (encoding != null) {
+					//this may be unnecessary
+					this.client.setEncoding(encoding);
+				}
+			}
+		} catch (Exception e) {
+			//don't care
+		}
+	}
+	
+    private final class QueryWorkItem implements Runnable {
+		private final ScriptReader reader;
+		String s;
+
+		private QueryWorkItem(String query) {
+			this.reader = new ScriptReader(new StringReader(query));
+		}
+
+		@Override
+		public void run() {
+			try {
+				if (s == null) {
+			        s = fixSQL(reader.readStatement());
+				}
+		        while (s != null) {
+		            try {
+		            	final StatementImpl stmt = connection.createStatement();
+		                executionFuture = stmt.submitExecute(s);
+		                executionFuture.addCompletionListener(new ResultsFuture.CompletionListener<Boolean>() {
+			        		@Override
+			        		public void onCompletion(ResultsFuture<Boolean> future) {
+			        			executionFuture = null;
+			        			try {
+					                if (future.get()) {
+					                	client.sendResults(s, stmt.getResultSet(), true);
+					                } else {
+					                	client.sendUpdateCount(s, stmt.getUpdateCount());
+					                	setEncoding();
+					                }
+					                s = fixSQL(reader.readStatement());
+			        			} catch (Throwable e) {
+			        				client.errorOccurred(e);
+			        				sync();
+			        				return;
+			        			} finally {
+			        				try {
+										stmt.close();
+									} catch (SQLException e) {
+										LogManager.logDetail(LogConstants.CTX_ODBC, e, "Error closing statement"); //$NON-NLS-1$
+									}
+			        			}
+			        			QueryWorkItem.this.run(); //continue processing
+			        		}
+						});
+		                return; //wait for the execution to finish
+		            } catch (SQLException e) {
+		                client.errorOccurred(e);
+		                break;
+		            } 
+		        }
+			} catch(IOException e) {
+				client.errorOccurred(e);
+			}
+			sync();
+		}
+	}
+
+	/**
      * Represents a PostgreSQL Prepared object.
      */
     static class Prepared {
 
-    	public Prepared (String name, String sql, PreparedStatement stmt, int[] paramType) {
+    	public Prepared (String name, String sql, PreparedStatementImpl stmt, int[] paramType) {
     		this.name = name;
     		this.sql = sql;
     		this.stmt = stmt;
@@ -633,7 +688,7 @@
         /**
          * The prepared statement.
          */
-        PreparedStatement stmt;
+        PreparedStatementImpl stmt;
 
         /**
          * The list of parameter types (if set).
@@ -646,7 +701,7 @@
      */
     static class Portal {
 
-    	public Portal(String name, String preparedName, String sql, PreparedStatement stmt, int[] resultColumnformat) {
+    	public Portal(String name, String preparedName, String sql, PreparedStatementImpl stmt, int[] resultColumnformat) {
     		this.name = name;
     		this.preparedName = preparedName;
     		this.sql = sql;
@@ -674,7 +729,7 @@
         /**
          * The prepared statement.
          */
-        PreparedStatement stmt;
+        PreparedStatementImpl stmt;
     }
 
 

Modified: trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -25,33 +25,47 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.Arrays;
 
 import org.teiid.core.util.ReflectionHelper;
+import org.teiid.jdbc.TeiidDriver;
+import org.teiid.logging.LogConstants;
+import org.teiid.logging.LogManager;
+import org.teiid.logging.MessageLevel;
 import org.teiid.net.CommunicationException;
 import org.teiid.net.socket.ObjectChannel;
 import org.teiid.net.socket.ServiceInvocationStruct;
 import org.teiid.odbc.ODBCClientRemote;
 import org.teiid.odbc.ODBCServerRemote;
 import org.teiid.odbc.ODBCServerRemoteImpl;
+import org.teiid.transport.PgFrontendProtocol.PGRequest;
 
 public class ODBCClientInstance implements ChannelListener{
 
 	private ODBCClientRemote client;
 	private ODBCServerRemoteImpl server;
 	private ReflectionHelper serverProxy = new ReflectionHelper(ODBCServerRemote.class);
+	private boolean hasPending;
 	
-	public ODBCClientInstance(final ObjectChannel channel, ODBCServerRemote.AuthenticationType authType) {
+	public ODBCClientInstance(final ObjectChannel channel, ODBCServerRemote.AuthenticationType authType, TeiidDriver driver) {
 		this.client = (ODBCClientRemote)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {ODBCClientRemote.class}, new InvocationHandler() {
 			@Override
 			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+				if (LogManager.isMessageToBeRecorded(LogConstants.CTX_ODBC, MessageLevel.TRACE)) {
+					LogManager.logTrace(LogConstants.CTX_ODBC, "invoking client method:", method.getName(), Arrays.deepToString(args)); //$NON-NLS-1$
+				}
 				ServiceInvocationStruct message = new ServiceInvocationStruct(args, method.getName(),ODBCServerRemote.class);
 				channel.write(message);
 				return null;
 			}
 		});
-		this.server = new ODBCServerRemoteImpl(this.client, authType);
+		this.server = new ODBCServerRemoteImpl(this, authType, driver);
 	}
 	
+	public ODBCClientRemote getClient() {
+		return client;
+	}
+	
 	@Override
 	public void disconnected() {
 		server.terminate();
@@ -61,6 +75,10 @@
 	public void exceptionOccurred(Throwable t) {
 		server.terminate();
 	}
+	
+	public boolean hasPending() {
+		return hasPending;
+	}
 
 	@Override
 	public void onConnection() throws CommunicationException {
@@ -68,8 +86,10 @@
 
 	@Override
 	public void receivedMessage(Object msg) throws CommunicationException {
-        if (msg instanceof ServiceInvocationStruct) {
-            processMessage((ServiceInvocationStruct)msg);
+        if (msg instanceof PGRequest) {
+        	PGRequest request = (PGRequest)msg;
+        	hasPending = request.hasPending;
+            processMessage(request.struct);
         }
 	}
 

Modified: trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -27,18 +27,24 @@
 import org.jboss.netty.channel.DefaultChannelPipeline;
 import org.jboss.netty.handler.ssl.SslHandler;
 import org.teiid.common.buffer.StorageManager;
+import org.teiid.jdbc.TeiidDriver;
 import org.teiid.net.socket.ObjectChannel;
 import org.teiid.odbc.ODBCServerRemote;
 
 public class ODBCSocketListener extends SocketListener {
 	private ODBCServerRemote.AuthenticationType authType = ODBCServerRemote.AuthenticationType.CLEARTEXT;
 	private int maxLobSize;
+	private TeiidDriver driver = TeiidDriver.getInstance();
 	
 	public ODBCSocketListener(SocketConfiguration config, StorageManager storageManager, int portOffset, int maxLobSize) {
 		//the clientserviceregistry isn't actually used by ODBC 
 		super(config, new ClientServiceRegistryImpl(ClientServiceRegistry.Type.ODBC), storageManager, portOffset);
 		this.maxLobSize = maxLobSize;
 	}
+	
+	public void setDriver(TeiidDriver driver) {
+		this.driver = driver;
+	}
 
 	@Override
 	protected SSLAwareChannelHandler createChannelPipelineFactory(final SSLConfiguration config, final StorageManager storageManager) {
@@ -60,7 +66,7 @@
 	
 	@Override
 	public ChannelListener createChannelListener(ObjectChannel channel) {
-		return new ODBCClientInstance(channel, this.authType);
+		return new ODBCClientInstance(channel, this.authType, driver);
 	}
 
 	public void setAuthenticationType(String value) {

Modified: trunk/runtime/src/main/java/org/teiid/transport/PGCharsetConverter.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/PGCharsetConverter.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/transport/PGCharsetConverter.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -29,44 +29,55 @@
  */
 public class PGCharsetConverter {
 	private static HashMap<String, Charset> charSetMap = new HashMap<String, Charset>();
-
+	private static HashMap<Charset, String> inverseCharSetMap = new HashMap<Charset, String>();
+	
 	static {
-		charSetMap.put("BIG5", Charset.forName("Big5")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("EUC_CN", Charset.forName("GB2312")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("EUC_JP", Charset.forName("EUC-JP")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("EUC_KR", Charset.forName("EUC-KR")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("EUC_TW", Charset.forName("EUC-TW")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("GB18030", Charset.forName("GB18030")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("GBK", Charset.forName("GBK")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("JOHAB", Charset.forName("JOHAB")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("KOI8", Charset.forName("KOI8-U")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("ISO_8859_5", Charset.forName("ISO-8859-5")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("ISO_8859_5", Charset.forName("ISO-8859-6")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("ISO_8859_5", Charset.forName("ISO-8859-7")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("ISO_8859_5", Charset.forName("ISO-8859-8")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN1", Charset.forName("ISO-8859-1")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN2", Charset.forName("ISO-8859-2")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN3", Charset.forName("ISO-8859-3")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN4", Charset.forName("ISO-8859-4")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN5", Charset.forName("ISO-8859-9")); //$NON-NLS-1$ //$NON-NLS-2$
-		//charSetMap.put("LATIN6", Charset.forName("ISO-8859-10")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN7", Charset.forName("ISO-8859-13")); //$NON-NLS-1$ //$NON-NLS-2$
-		//charSetMap.put("LATIN8", Charset.forName("ISO-8859-14")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("LATIN9", Charset.forName("ISO-8859-15")); //$NON-NLS-1$ //$NON-NLS-2$
-		//charSetMap.put("LATIN10", Charset.forName("ISO-8859-16")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("SJIS", Charset.forName("windows-932")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("UHC", Charset.forName("windows-949")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("UTF8", Charset.forName("UTF-8")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN866", Charset.forName("cp866")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN874", Charset.forName("cp874")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN1250", Charset.forName("windows-1250")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN1251", Charset.forName("windows-1251")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN1252", Charset.forName("windows-1252")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN1256", Charset.forName("windows-1256")); //$NON-NLS-1$ //$NON-NLS-2$
-		charSetMap.put("WIN1258", Charset.forName("windows-1258")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("BIG5", Charset.forName("Big5")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("EUC_CN", Charset.forName("GB2312")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("EUC_JP", Charset.forName("EUC-JP")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("EUC_KR", Charset.forName("EUC-KR")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("EUC_TW", Charset.forName("EUC-TW")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("GB18030", Charset.forName("GB18030")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("GBK", Charset.forName("GBK")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("JOHAB", Charset.forName("JOHAB")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("KOI8", Charset.forName("KOI8-U")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("ISO_8859_5", Charset.forName("ISO-8859-5")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("ISO_8859_5", Charset.forName("ISO-8859-6")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("ISO_8859_5", Charset.forName("ISO-8859-7")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("ISO_8859_5", Charset.forName("ISO-8859-8")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN1", Charset.forName("ISO-8859-1")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN2", Charset.forName("ISO-8859-2")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN3", Charset.forName("ISO-8859-3")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN4", Charset.forName("ISO-8859-4")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN5", Charset.forName("ISO-8859-9")); //$NON-NLS-1$ //$NON-NLS-2$
+		//mapCharset("LATIN6", Charset.forName("ISO-8859-10")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN7", Charset.forName("ISO-8859-13")); //$NON-NLS-1$ //$NON-NLS-2$
+		//mapCharset("LATIN8", Charset.forName("ISO-8859-14")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("LATIN9", Charset.forName("ISO-8859-15")); //$NON-NLS-1$ //$NON-NLS-2$
+		//mapCharset("LATIN10", Charset.forName("ISO-8859-16")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("SJIS", Charset.forName("windows-932")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("UHC", Charset.forName("windows-949")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("UTF8", Charset.forName("UTF-8")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("UNICODE", Charset.forName("UTF-8")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN866", Charset.forName("cp866")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN874", Charset.forName("cp874")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN1250", Charset.forName("windows-1250")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN1251", Charset.forName("windows-1251")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN1252", Charset.forName("windows-1252")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN1256", Charset.forName("windows-1256")); //$NON-NLS-1$ //$NON-NLS-2$
+		mapCharset("WIN1258", Charset.forName("windows-1258")); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 	
+	private static void mapCharset(String name, Charset cs) {
+		charSetMap.put(name, cs);
+		inverseCharSetMap.put(cs, name);
+	}
+	
 	public static Charset getCharset(String name) {
 		return charSetMap.get(name);
 	}
+	
+	public static String getEncoding(Charset cs) {
+		return inverseCharSetMap.get(cs);
+	}
 }

Modified: trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -24,6 +24,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.io.StreamCorruptedException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.charset.Charset;
@@ -44,14 +45,17 @@
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.Channels;
 import org.jboss.netty.channel.MessageEvent;
+import org.teiid.client.util.ResultsFuture;
 import org.teiid.core.util.ObjectConverterUtil;
 import org.teiid.core.util.ReaderInputStream;
 import org.teiid.core.util.ReflectionHelper;
+import org.teiid.jdbc.ResultSetImpl;
 import org.teiid.jdbc.TeiidSQLException;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
 import org.teiid.net.socket.ServiceInvocationStruct;
 import org.teiid.odbc.ODBCClientRemote;
+import org.teiid.transport.pg.PGbytea;
 
 /**
  * Represents the messages going from Server --> PG ODBC Client  
@@ -60,8 +64,74 @@
 @SuppressWarnings("nls")
 public class PgBackendProtocol implements ChannelDownstreamHandler, ODBCClientRemote {
 	
-    private static final int PG_TYPE_VARCHAR = 1043;
+    private final class ResultsWorkItem implements Runnable {
+		private final int[] types;
+		private final String sql;
+		private final int columns;
+		private final ResultSetImpl rs;
 
+		private ResultsWorkItem(int[] types, String sql, int columns,
+				ResultSetImpl rs) {
+			this.types = types;
+			this.sql = sql;
+			this.columns = columns;
+			this.rs = rs;
+		}
+
+		@Override
+		public void run() {
+			while (true) {
+				try {
+			    	nextFuture = rs.submitNext();
+			    	if (!nextFuture.isDone()) {
+				    	nextFuture.addCompletionListener(new ResultsFuture.CompletionListener<Boolean>() {
+				    		@Override
+				    		public void onCompletion(ResultsFuture<Boolean> future) {
+				    			if (processRow(future)) {
+				    				//this can be recursive, but ideally won't be called many times 
+				    				ResultsWorkItem.this.run();
+				    			}
+				    		}
+						});
+				    	return;
+			    	}
+			    	if (!processRow(nextFuture)) {
+			    		break;
+			    	}
+				} catch (Throwable t) {
+					try {
+						sendErrorResponse(t);
+					} catch (IOException e) {
+						terminate(e);
+					}
+				}
+			}
+		}
+		
+		private boolean processRow(ResultsFuture<Boolean> future) {
+			nextFuture = null;
+			boolean processNext = true;
+			try {
+    			if (future.get()) {
+    				sendDataRow(rs, columns, types);
+    			} else {
+    				sendCommandComplete(sql, 0);
+    				processNext = false;
+    			}
+			} catch (Throwable t) {
+				try {
+					sendErrorResponse(t);
+				} catch (IOException e) {
+					terminate(e);
+				}
+				return false;
+			}
+			return processNext;
+		}
+	}
+
+	private static final int PG_TYPE_VARCHAR = 1043;
+
     private static final int PG_TYPE_BOOL = 16;
     private static final int PG_TYPE_BYTEA = 17;
     private static final int PG_TYPE_BPCHAR = 1042;
@@ -125,7 +195,7 @@
 	@Override
 	public void initialized(Properties props) {
 		this.props = props;
-		this.encoding = Charset.forName(props.getProperty("client_encoding", "UTF-8"));
+		setEncoding(props.getProperty("client_encoding", "UTF-8"));
 	}
 	
 	@Override
@@ -149,7 +219,7 @@
 			// releases before 8.1; IntervalStyle was not reported by releases before 8.4; 
 			// application_name was not reported by releases before 9.0.)
 			
-			sendParameterStatus("client_encoding", this.encoding.name());
+			sendParameterStatus("client_encoding", PGCharsetConverter.getEncoding(this.encoding));
 			sendParameterStatus("DateStyle", this.props.getProperty("DateStyle", "ISO"));
 			sendParameterStatus("integer_datetimes", "off");
 			sendParameterStatus("is_superuser", "off");
@@ -205,9 +275,10 @@
 		}
 	}
 	
-	public void setEncoding(Charset value) {
-		if (value != null) {
-			this.encoding = value;
+	public void setEncoding(String value) {
+		Charset cs = PGCharsetConverter.getCharset(value);
+		if (cs != null) {
+			this.encoding = cs;
 		}
 	}
 
@@ -248,24 +319,27 @@
 			terminate(e);
 		}
 	}
+	
+	private volatile ResultsFuture<Boolean> nextFuture;
 
 	@Override
-	public void sendResults(String sql, ResultSet rs, boolean describeRows) {
+	public void sendResults(final String sql, final ResultSetImpl rs, boolean describeRows) {
 		try {
+			if (nextFuture != null) {
+				sendErrorResponse(new IllegalStateException("Pending results have not been sent")); //$NON-NLS-1$
+			}
             try {
             	if (describeRows) {
             		ResultSetMetaData meta = rs.getMetaData();
             		sendRowDescription(meta);
             	}
-            	int columns = rs.getMetaData().getColumnCount();
-            	int[] types = new int[columns];
+            	final int columns = rs.getMetaData().getColumnCount();
+            	final int[] types = new int[columns];
             	for(int i = 0; i < columns; i++) {
             		types[i] = rs.getMetaData().getColumnType(i+1);
             	}
-                while (rs.next()) {
-                    sendDataRow(rs, columns, types);
-                }
-                sendCommandComplete(sql, 0);
+            	Runnable r = new ResultsWorkItem(types, sql, columns, rs);
+            	r.run();                
 			} catch (SQLException e) {
 				sendErrorResponse(e);
 			}			
@@ -317,7 +391,7 @@
 	}
 	
 	private void terminate(Throwable t) {
-		trace("channel being terminated - "+t.getMessage());
+		trace("channel being terminated - ", t.getMessage());
 		this.ctx.getChannel().close();
 	}
 
@@ -342,7 +416,7 @@
 		} else if (sql.startsWith("BEGIN")) {
 			tag = "BEGIN";
 		} else {
-			trace("Check command tag: " + sql);
+			trace("Check command tag:", sql);
 			tag = "UPDATE " + updateCount;
 		}
 		writeString(tag);
@@ -367,6 +441,7 @@
 	private byte[] getContent(ResultSet rs, int type, int column) throws SQLException, TeiidSQLException, IOException {
 		byte[] bytes = null;
 		switch (type) {
+			case Types.BIT:
 		    case Types.BOOLEAN:
 		    case Types.VARCHAR:       
 		    case Types.CHAR:
@@ -408,7 +483,11 @@
 		    case Types.BLOB:
 		    	Blob blob = rs.getBlob(column);
 		    	if (blob != null) {
-		    		bytes = toHex(ObjectConverterUtil.convertToByteArray(blob.getBinaryStream(), this.maxLobSize));
+		    		try {
+			    		bytes = PGbytea.toPGString(ObjectConverterUtil.convertToByteArray(blob.getBinaryStream(), this.maxLobSize)).getBytes(this.encoding);
+		    		} catch(OutOfMemoryError e) {
+		    			throw new StreamCorruptedException("data too big: " + e.getMessage()); //$NON-NLS-1$ 
+		    		}
 		    	}
 		    	break;
 		    default:
@@ -491,7 +570,7 @@
 	}
 
 	private void sendErrorResponse(String message) throws IOException {
-		trace("Exception: " + message);
+		trace("Exception:", message);
 		startMessage('E');
 		write('S');
 		writeString("ERROR");
@@ -504,7 +583,7 @@
 	}
 	
 	private void sendNoticeResponse(String message) throws IOException {
-		trace("notice: " + message);
+		trace("notice:", message);
 		startMessage('N');
 		write('S');
 		writeString("ERROR");
@@ -636,12 +715,11 @@
 		buffer.writeByte((byte)this.messageType);
 		buffer.writeInt(len+4);
 		buffer.writeBytes(buff);
-
 		Channels.write(this.ctx, this.message.getFuture(), buffer, this.message.getRemoteAddress());
 	}
-  
-	private static void trace(String msg) {
-		LogManager.logTrace(LogConstants.CTX_ODBC, msg);
+
+	private static void trace(String... msg) {
+		LogManager.logTrace(LogConstants.CTX_ODBC, (Object[])msg);
 	}
 	
 	/**
@@ -695,26 +773,5 @@
             return PG_TYPE_UNKNOWN;
         }
     }
-    
-	private static final byte[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e','f' };
 	
-	/**
-	 * When sending the byteA content to client convert into Hex before sending the content.
-	 * @param b
-	 * @return
-	 * @throws IOException
-	 */
-	static byte[] toHex(byte[] b) throws IOException {
-		byte[] hexbytes = PgFrontendProtocol.createByteArray((2 * b.length)+2);
-		hexbytes[0] = '\\';
-		hexbytes[1] = 'x';
-			
-		for (int i = 0; i < b.length; i++) {
-			int index = (i*2)+2;
-			int v = b[i] & 0xff;
-			hexbytes[index] = hexChars[v >> 4];
-			hexbytes[index+1] = hexChars[v & 0xf];
-		}
-		return hexbytes;
-	}      
 }

Modified: trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -29,6 +29,8 @@
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.nio.charset.Charset;
+import java.util.Arrays;
 import java.util.Properties;
 
 import org.jboss.netty.buffer.ChannelBuffer;
@@ -37,6 +39,7 @@
 import org.jboss.netty.handler.codec.frame.FrameDecoder;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
+import org.teiid.logging.MessageLevel;
 import org.teiid.net.socket.ServiceInvocationStruct;
 import org.teiid.odbc.ODBCServerRemote;
 
@@ -60,9 +63,9 @@
 	private Byte messageType;
 	private Integer dataLength;
 	private boolean initialized = false;
-	private String encoding = "UTF-8"; // client can override this
+	private Charset encoding = Charset.forName("UTF-8"); // client can override this
 	private ODBCServerRemote odbcProxy;
-	private ServiceInvocationStruct message;
+	private PGRequest message;
 	private String user;
 	private String databaseName;
 	
@@ -72,17 +75,17 @@
             throw new IllegalArgumentException("maxObjectSize: " + maxObjectSize); //$NON-NLS-1$
         }
 		
-		if (encoding == null) {
-			this.encoding = "UTF-8"; //$NON-NLS-1$ 
-		}
-        		
 		this.maxObjectSize = maxObjectSize;
 		
 		// the proxy is used for generating the object based message based on ServiceInvocationStruct class.
 		this.odbcProxy = (ODBCServerRemote)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {ODBCServerRemote.class}, new InvocationHandler() {
 			@Override
 			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-				message = new ServiceInvocationStruct(args, method.getName(),ODBCServerRemote.class);
+				if (LogManager.isMessageToBeRecorded(LogConstants.CTX_ODBC, MessageLevel.TRACE)) {
+					LogManager.logTrace(LogConstants.CTX_ODBC, "invoking server method:", method.getName(), Arrays.deepToString(args)); //$NON-NLS-1$
+				}
+				message = new PGRequest();
+				message.struct = new ServiceInvocationStruct(args, method.getName(),ODBCServerRemote.class);
 				return null;
 			}
 		});
@@ -126,8 +129,9 @@
         }
 
         byte[] data = createByteArray(this.dataLength - 4);
-        buffer.readBytes(data);      
-		Object message =  createRequestMessage(this.messageType, new NullTerminatedStringDataInputStream(new DataInputStream(new ByteArrayInputStream(data, 0, this.dataLength-4)), this.encoding));
+        buffer.readBytes(data);
+		createRequestMessage(this.messageType, new NullTerminatedStringDataInputStream(new DataInputStream(new ByteArrayInputStream(data, 0, this.dataLength-4)), this.encoding));
+		message.hasPending = buffer.readableBytes() > 0;
 		this.dataLength = null;
 		this.messageType = null;
 		return message;
@@ -166,25 +170,21 @@
 	}
 
 	private Object buildError() {
-		trace("error");
 		this.odbcProxy.unsupportedOperation("option not suported");
 		return message;
 	}
 
 	private Object buildFlush() {
-		trace("flush");
 		this.odbcProxy.flush();
 		return message;
 	}
 
 	private Object buildTeminate() {
-		trace("terminate");
 		this.odbcProxy.terminate();
 		return message;
 	}
 
 	private Object buildInitialize(NullTerminatedStringDataInputStream data) throws IOException{
-        trace("Init");
         Properties props = new Properties();
        
         int version = data.readInt();
@@ -197,8 +197,7 @@
         	return message;
         }
         
-        trace("StartupMessage");
-        trace(" version " + version + " (" + (version >> 16) + "." + (version & 0xff) + ")");
+        trace("StartupMessage version", version, "(", (version >> 16), ".", (version & 0xff), ")");
         
         while (true) {
             String param =  data.readString();
@@ -207,24 +206,25 @@
             }
             String value =  data.readString();
             props.setProperty(param, value);
-            trace(" param " + param + "=" + value);
         }        
         this.user = props.getProperty("user");
         this.databaseName = props.getProperty("database");
-        this.encoding = props.getProperty("client_encoding", "UTF-8");
+        String clientEncoding = props.getProperty("client_encoding", "UTF-8");
+        Charset cs = PGCharsetConverter.getCharset(clientEncoding);
+        if (cs != null) {
+        	this.encoding = cs;
+        }
         this.odbcProxy.initialize(props);
         return message;
 	}
 	
 	private Object buildLogin(NullTerminatedStringDataInputStream data) throws IOException{
-        trace("PasswordMessage");
         String password = data.readString();
         this.odbcProxy.logon(this.databaseName, this.user, password);
         return message;
 	}	
 
 	private Object buildParse(NullTerminatedStringDataInputStream data) throws IOException {
-        trace("Parse");
         String name = data.readString();
         String sql = data.readString();
         
@@ -242,7 +242,6 @@
 	}	
 
 	private Object buildBind(NullTerminatedStringDataInputStream data) throws IOException {
-        trace("Bind");
         String bindName = data.readString();
         String prepName = data.readString();
         
@@ -279,7 +278,6 @@
 
 	private Object buildExecute(NullTerminatedStringDataInputStream data) throws IOException {
 		String portalName = data.readString();
-		trace("Execute "+ portalName);
         int maxRows = data.readShort();
         this.odbcProxy.execute(portalName, maxRows);
         return message;
@@ -289,7 +287,6 @@
 	private Object buildDescribe(NullTerminatedStringDataInputStream data)  throws IOException{
         char type = (char) data.readByte();
         String name = data.readString();
-        trace("Describe");
         if (type == 'S') {
         	this.odbcProxy.getParameterDescription(name);
         	return message;
@@ -297,7 +294,7 @@
         	this.odbcProxy.getResultSetMetaDataDescription(name);
         	return message;
         } else {
-            trace("expected S or P, got " + type);
+            trace("expected S or P, got ", type);
             this.odbcProxy.unsupportedOperation("expected S or P");
             return message;
         }
@@ -305,14 +302,12 @@
 	
 
 	private Object buildSync() {
-		trace("sync");
 		this.odbcProxy.sync();
 		return message;
 	}	
 
 	private Object buildExecuteQuery(NullTerminatedStringDataInputStream data) throws IOException {
         String query = data.readString();
-        trace("Query:"+query);
         this.odbcProxy.executeQuery(query);
         return message;
 	}	
@@ -400,10 +395,15 @@
 		return content;
 	}
 	
+	public static class PGRequest {
+		ServiceInvocationStruct struct;
+		boolean hasPending;
+	}
+	
 	static class NullTerminatedStringDataInputStream extends DataInputStream{
-		private String encoding;
+		private Charset encoding;
 		
-		public NullTerminatedStringDataInputStream(DataInputStream in, String encoding) {
+		public NullTerminatedStringDataInputStream(DataInputStream in, Charset encoding) {
 			super(in);
 			this.encoding = encoding;
 		}
@@ -421,7 +421,7 @@
 	    }
 	}
 	
-	private static void trace(String msg) {
+	private static void trace(Object... msg) {
 		LogManager.logTrace(LogConstants.CTX_ODBC, msg);
 	}
 }

Added: trunk/runtime/src/main/java/org/teiid/transport/pg/PGbytea.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/pg/PGbytea.java	                        (rev 0)
+++ trunk/runtime/src/main/java/org/teiid/transport/pg/PGbytea.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -0,0 +1,176 @@
+/*-------------------------------------------------------------------------
+*
+* Copyright (c) 2003-2008, PostgreSQL Global Development Group
+*
+* IDENTIFICATION
+*   $PostgreSQL: pgjdbc/org/postgresql/util/PGbytea.java,v 1.17 2010/04/06 23:45:09 jurka Exp $
+*
+*-------------------------------------------------------------------------
+*/
+package org.teiid.transport.pg;
+
+import java.sql.SQLException;
+
+/**
+ * Converts to and from the postgresql bytea datatype used by the backend.
+ */
+public class PGbytea
+{
+    private static final int MAX_3_BUFF_SIZE = 2 * 1024 * 1024;
+
+    /*
+     * Converts a PG bytea raw value (i.e. the raw binary representation
+     * of the bytea data type) into a java byte[]
+     */
+    public static byte[] toBytes(byte[] s) throws SQLException
+    {
+        if (s == null)
+            return null;
+
+        // Starting with PG 9.0, a new hex format is supported
+        // that starts with "\x".  Figure out which format we're
+        // dealing with here.
+        //
+        if (s.length < 2 || s[0] != '\\' || s[1] != 'x') {
+            return toBytesOctalEscaped(s);
+        }
+        return toBytesHexEscaped(s);
+    }
+
+    private static byte[] toBytesHexEscaped(byte[] s)
+    {
+        byte[] output = new byte[(s.length - 2) / 2];
+        for (int i=0; i<output.length; i++) {
+            byte b1 = gethex(s[2 + i*2]);
+            byte b2 = gethex(s[2 + i*2 + 1]);
+            output[i] = (byte)((b1 << 4) | b2);
+        }
+        return output;
+    }
+
+    private static byte gethex(byte b) {
+        // 0-9 == 48-57
+        if (b <= 57)
+            return (byte)(b - 48);
+
+        // a-f == 97-102
+        if (b >= 97)
+            return (byte)(b - 97 + 10);
+
+        // A-F == 65-70
+        return (byte)(b - 65 + 10);
+    }
+
+    private static byte[] toBytesOctalEscaped(byte[] s)
+    {
+        final int slength = s.length;
+        byte[] buf = null;
+        int correctSize = slength;
+        if (slength > MAX_3_BUFF_SIZE)
+        {
+            // count backslash escapes, they will be either
+            // backslashes or an octal escape \\ or \003
+            //
+            for (int i = 0; i < slength; ++i)
+            {
+                byte current = s[i];
+                if (current == '\\')
+                {
+                    byte next = s[ ++i ];
+                    if (next == '\\')
+                    {
+                        --correctSize;
+                    }
+                    else
+                    {
+                        correctSize -= 3;
+                    }
+                }
+            }
+            buf = new byte[correctSize];
+        }
+        else
+        {
+            buf = new byte[slength];
+        }
+        int bufpos = 0;
+        int thebyte;
+        byte nextbyte;
+        byte secondbyte;
+        for (int i = 0; i < slength; i++)
+        {
+            nextbyte = s[i];
+            if (nextbyte == (byte)'\\')
+            {
+                secondbyte = s[++i];
+                if (secondbyte == (byte)'\\')
+                {
+                    //escaped \
+                    buf[bufpos++] = (byte)'\\';
+                }
+                else
+                {
+                    thebyte = (secondbyte - 48) * 64 + (s[++i] - 48) * 8 + (s[++i] - 48);
+                    if (thebyte > 127)
+                        thebyte -= 256;
+                    buf[bufpos++] = (byte)thebyte;
+                }
+            }
+            else
+            {
+                buf[bufpos++] = nextbyte;
+            }
+        }
+        if (bufpos == correctSize)
+        {
+            return buf;
+        }
+        byte[] l_return = new byte[bufpos];
+        System.arraycopy(buf, 0, l_return, 0, bufpos);
+        return l_return;
+    }
+
+    /*
+     * Converts a java byte[] into a PG bytea string (i.e. the text
+     * representation of the bytea data type)
+     */
+    public static String toPGString(byte[] p_buf) throws SQLException
+    {
+        if (p_buf == null)
+            return null;
+        StringBuffer l_strbuf = new StringBuffer(2 * p_buf.length);
+        for (int i = 0; i < p_buf.length; i++)
+        {
+            int l_int = (int)p_buf[i];
+            if (l_int < 0)
+            {
+                l_int = 256 + l_int;
+            }
+            //we escape the same non-printable characters as the backend
+            //we must escape all 8bit characters otherwise when convering
+            //from java unicode to the db character set we may end up with
+            //question marks if the character set is SQL_ASCII
+            if (l_int < 040 || l_int > 0176)
+            {
+                //escape charcter with the form \000, but need two \\ because of
+                //the Java parser
+                l_strbuf.append("\\");
+                l_strbuf.append((char)(((l_int >> 6) & 0x3) + 48));
+                l_strbuf.append((char)(((l_int >> 3) & 0x7) + 48));
+                l_strbuf.append((char)((l_int & 0x07) + 48));
+            }
+            else if (p_buf[i] == (byte)'\\')
+            {
+                //escape the backslash character as \\, but need four \\\\ because
+                //of the Java parser
+                l_strbuf.append("\\\\");
+            }
+            else
+            {
+                //other characters are left alone
+                l_strbuf.append((char)p_buf[i]);
+            }
+        }
+        return l_strbuf.toString();
+    }
+}
\ No newline at end of file


Property changes on: trunk/runtime/src/main/java/org/teiid/transport/pg/PGbytea.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/test-integration/common/pom.xml
===================================================================
--- trunk/test-integration/common/pom.xml	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/test-integration/common/pom.xml	2011-03-25 05:39:33 UTC (rev 3034)
@@ -9,5 +9,12 @@
 	<artifactId>test-integration-common</artifactId>
 	<name>Common Integration Tests</name>
 	<description>Common Integration tests that do not require external dependencies</description>
+	<dependencies>
+		<dependency>
+			<groupId>postgresql</groupId>
+			<artifactId>postgresql</artifactId>
+			<version>8.3-606.jdbc3</version>
+		</dependency>
+	</dependencies>
      
 </project>
\ No newline at end of file

Modified: trunk/test-integration/common/src/test/java/org/teiid/jdbc/FakeServer.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/jdbc/FakeServer.java	2011-03-24 15:26:19 UTC (rev 3033)
+++ trunk/test-integration/common/src/test/java/org/teiid/jdbc/FakeServer.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -48,6 +48,8 @@
 import org.teiid.metadata.Schema;
 import org.teiid.metadata.index.IndexMetadataFactory;
 import org.teiid.metadata.index.VDBMetadataFactory;
+import org.teiid.net.CommunicationException;
+import org.teiid.net.ConnectionException;
 import org.teiid.query.function.SystemFunctionManager;
 import org.teiid.query.metadata.TransformationMetadata.Resource;
 import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
@@ -59,7 +61,7 @@
 import org.teiid.transport.LogonImpl;
 
 @SuppressWarnings("nls")
-public class FakeServer extends ClientServiceRegistryImpl {
+public class FakeServer extends ClientServiceRegistryImpl implements ConnectionProfile {
 
 	SessionServiceImpl sessionService = new SessionServiceImpl();
 	LogonImpl logon;
@@ -161,14 +163,26 @@
 		final Properties p = new Properties();
 		TeiidDriver.parseURL(embeddedURL, p);
 
-		LocalServerConnection conn = new LocalServerConnection(p) {
-			@Override
-			protected ClientServiceRegistry getClientServiceRegistry() {
-				return FakeServer.this;
-			}
-		};
-		return new ConnectionImpl(conn, p, embeddedURL);
+		return connect(embeddedURL, p);
 	}
 	
+	@Override
+	public ConnectionImpl connect(String url, Properties info)
+			throws TeiidSQLException {
+		LocalServerConnection conn;
+		try {
+			conn = new LocalServerConnection(info) {
+				@Override
+				protected ClientServiceRegistry getClientServiceRegistry() {
+					return FakeServer.this;
+				}
+			};
+		} catch (CommunicationException e) {
+			throw TeiidSQLException.create(e);
+		} catch (ConnectionException e) {
+			throw TeiidSQLException.create(e);
+		}
+		return new ConnectionImpl(conn, info, url);	
+	}
 	
 }

Added: trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java	                        (rev 0)
+++ trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java	2011-03-25 05:39:33 UTC (rev 3034)
@@ -0,0 +1,132 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.transport;
+
+import static org.junit.Assert.*;
+
+import java.net.InetSocketAddress;
+import java.nio.charset.Charset;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Properties;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.postgresql.Driver;
+import org.teiid.common.buffer.BufferManagerFactory;
+import org.teiid.core.util.UnitTestUtil;
+import org.teiid.jdbc.FakeServer;
+import org.teiid.jdbc.TeiidDriver;
+import org.teiid.jdbc.TestMMDatabaseMetaData;
+
+ at SuppressWarnings("nls")
+public class TestODBCSocketTransport {
+
+	static InetSocketAddress addr;
+	static ODBCSocketListener odbcTransport;
+	
+	@BeforeClass public static void oneTimeSetup() throws Exception {
+		SocketConfiguration config = new SocketConfiguration();
+		config.setSSLConfiguration(new SSLConfiguration());
+		addr = new InetSocketAddress(0);
+		config.setBindAddress(addr.getHostName());
+		config.setPortNumber(0);
+		odbcTransport = new ODBCSocketListener(config, BufferManagerFactory.getStandaloneBufferManager(), 0, 100000);
+		
+		FakeServer server = new FakeServer();
+		server.deployVDB("parts", UnitTestUtil.getTestDataPath() + "/PartsSupplier.vdb");
+		
+		TeiidDriver driver = new TeiidDriver();
+		driver.setEmbeddedProfile(server);
+		odbcTransport.setDriver(driver);
+		
+	}
+	
+	@AfterClass public static void oneTimeTearDown() throws Exception {
+		if (odbcTransport != null) {
+			odbcTransport.stop();
+		}
+	}
+	
+	Connection conn;
+	
+	@Before public void setUp() throws Exception {
+		/*Logger logger = Logger.getLogger(LogConstants.CTX_ODBC);
+		logger.setLevel(Level.FINEST);
+		ConsoleHandler handler = new ConsoleHandler();
+		handler.setLevel(Level.FINEST);
+		logger.addHandler(handler);*/
+		
+		Driver d = new Driver();
+		Properties p = new Properties();
+		p.setProperty("user", "testuser");
+		p.setProperty("password", "testpassword");
+		conn = d.connect("jdbc:postgresql://"+addr.getHostName()+":" +odbcTransport.getPort()+"/parts", p);
+	}
+	
+	@After public void tearDown() throws Exception {
+		if (conn != null) {
+			conn.close();
+		}
+	}
+	
+	/**
+	 * Under the covers this still executes a prepared statement due to the driver handling
+	 */
+	@Test public void testSelect() throws Exception {
+		Statement s = conn.createStatement();
+		assertTrue(s.execute("select * from tables order by name"));
+		TestMMDatabaseMetaData.compareResultSet(s.getResultSet());
+	}
+	
+	@Test public void testBlob() throws Exception {
+		Statement s = conn.createStatement();
+		assertTrue(s.execute("select to_bytes('abc', 'UTF-16')"));
+		ResultSet rs = s.getResultSet();
+		assertTrue(rs.next());
+		byte[] bytes = rs.getBytes(1);
+		assertEquals("abc", new String(bytes, Charset.forName("UTF-16")));
+	}
+	
+	@Test public void testClob() throws Exception {
+		Statement s = conn.createStatement();
+		assertTrue(s.execute("select cast('abc' as clob)"));
+		ResultSet rs = s.getResultSet();
+		assertTrue(rs.next());
+		//getting as a clob is unsupported, since it uses the lo logic
+		String clob = rs.getString(1);
+		assertEquals("abc", clob);
+	}
+
+	@Test public void testTransactionCycle() throws Exception {
+		//TODO: drill in to ensure that the underlying statement has been set to autocommit false
+		conn.setAutoCommit(false); 
+		Statement s = conn.createStatement();
+		assertTrue(s.execute("select * from tables order by name"));
+		conn.setAutoCommit(true);
+	}
+}


Property changes on: trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/test-integration/common/src/test/resources/TestODBCSocketTransport/testSelect.expected
===================================================================
--- trunk/test-integration/common/src/test/resources/TestODBCSocketTransport/testSelect.expected	                        (rev 0)
+++ trunk/test-integration/common/src/test/resources/TestODBCSocketTransport/testSelect.expected	2011-03-25 05:39:33 UTC (rev 3034)
@@ -0,0 +1,46 @@
+varchar                                                            varchar                                                            varchar                                                            varchar                                                            varchar                                                            bool        bool             varchar                                                            int4         varchar                                                            bool      bool            int4       
+vdbname                                                            schemaname                                                         name                                                               type                                                               nameinsource                                                       isphysical  supportsupdates  uid                                                                cardinality  description                                                        issystem  ismaterialized  oid        
+parts                                                              SYS                                                                Columns                                                            Table                                                              <null>                                                             true        false            mmuuid:1c9a5cb2-17b1-4e4a-8b0e-3a42bd052509                        0            <null>                                                             true      false           7          
+parts                                                              SYS                                                                DataTypes                                                          Table                                                              <null>                                                             true        false            mmuuid:9a8794f9-66f8-49e8-8576-89d212d0f957                        0            <null>                                                             true      false           8          
+parts                                                              SYS                                                                KeyColumns                                                         Table                                                              <null>                                                             true        false            mmuuid:14946083-3bd5-42d5-8283-1c0694347c29                        0            <null>                                                             true      false           9          
+parts                                                              SYS                                                                Keys                                                               Table                                                              <null>                                                             true        false            mmuuid:1e5135dc-ce5d-4b25-a8ff-63f5440b3108                        0            <null>                                                             true      false           10         
+parts                                                              SYSADMIN                                                           MatViews                                                           Table                                                              <null>                                                             true        false            mmuuid:520ba1e8-3553-460f-8d18-9b43f089e256                        0            <null>                                                             true      false           5          
+parts                                                              PartsSupplier                                                      PARTSSUPPLIER.PARTS                                                Table                                                              PARTS                                                              true        true             mmuuid:f6276601-73fe-1edc-a81c-ecf397b10590                        16           <null>                                                             false     false           0          
+parts                                                              PartsSupplier                                                      PARTSSUPPLIER.SHIP_VIA                                             Table                                                              SHIP_VIA                                                           true        true             mmuuid:0f4e9b80-73ff-1edc-a81c-ecf397b10590                        4            <null>                                                             false     false           1          
+parts                                                              PartsSupplier                                                      PARTSSUPPLIER.STATUS                                               Table                                                              STATUS                                                             true        true             mmuuid:1f297200-73ff-1edc-a81c-ecf397b10590                        3            <null>                                                             false     false           2          
+parts                                                              PartsSupplier                                                      PARTSSUPPLIER.SUPPLIER                                             Table                                                              SUPPLIER                                                           true        true             mmuuid:2c371ec0-73ff-1edc-a81c-ecf397b10590                        16           <null>                                                             false     false           4          
+parts                                                              PartsSupplier                                                      PARTSSUPPLIER.SUPPLIER_PARTS                                       Table                                                              SUPPLIER_PARTS                                                     true        true             mmuuid:3deafb00-73ff-1edc-a81c-ecf397b10590                        227          <null>                                                             false     false           3          
+parts                                                              SYS                                                                ProcedureParams                                                    Table                                                              <null>                                                             true        false            mmuuid:a56bd7fe-c87a-411c-8f5d-661975a25626                        0            <null>                                                             true      false           11         
+parts                                                              SYS                                                                Procedures                                                         Table                                                              <null>                                                             true        false            mmuuid:0bc132a5-9f8d-4a3c-9f5d-98156a98a962                        0            <null>                                                             true      false           12         
+parts                                                              SYS                                                                Properties                                                         Table                                                              <null>                                                             true        false            mmuuid:7a45e50a-d03f-4548-ba35-761651bbca85                        0            <null>                                                             true      false           13         
+parts                                                              SYS                                                                ReferenceKeyColumns                                                Table                                                              <null>                                                             true        false            mmuuid:6a9653e8-a337-41b2-86fa-77b98f409a29                        0            <null>                                                             true      false           14         
+parts                                                              SYS                                                                Schemas                                                            Table                                                              <null>                                                             true        false            mmuuid:8648a554-b2ad-4e8e-84ca-2ec618b311a9                        0            <null>                                                             true      false           15         
+parts                                                              SYS                                                                Tables                                                             Table                                                              <null>                                                             true        false            mmuuid:8551b3bd-11cc-4049-9bcf-fe91a0eb7ba7                        0            <null>                                                             true      false           16         
+parts                                                              SYSADMIN                                                           VDBResources                                                       Table                                                              <null>                                                             true        false            mmuuid:1785804d-beaf-4831-9531-e59164fedd49                        0            <null>                                                             true      false           6          
+parts                                                              SYS                                                                VirtualDatabases                                                   Table                                                              <null>                                                             true        false            mmuuid:47297c72-d621-4f4e-af4e-74060ac5f489                        0            <null>                                                             true      false           17         
+parts                                                              pg_catalog                                                         pg_am                                                              Table                                                              <null>                                                             false       false            mmuid:1462b28e-0bab-436f-9654-013821506337                         0            <null>                                                             true      false           23         
+parts                                                              pg_catalog                                                         pg_attrdef                                                         Table                                                              <null>                                                             false       false            mmuid:71091853-c65e-46a9-9947-aa024f806e2d                         0            <null>                                                             true      false           26         
+parts                                                              pg_catalog                                                         pg_attribute                                                       Table                                                              <null>                                                             false       false            mmuid:fa463d98-365f-489a-a707-025193cb51eb                         0            <null>                                                             true      true            20         
+parts                                                              pg_catalog                                                         pg_class                                                           Table                                                              <null>                                                             false       false            mmuid:7e21f2e6-06e3-4bca-9b01-72ea47821560                         0            <null>                                                             true      true            19         
+parts                                                              pg_catalog                                                         pg_database                                                        Table                                                              <null>                                                             false       false            mmuid:492dd834-907f-429b-aa6e-958ad65204c6                         0            <null>                                                             true      false           27         
+parts                                                              pg_catalog                                                         pg_index                                                           Table                                                              <null>                                                             false       false            mmuid:22ac431d-e6e6-4eef-9d74-b31795424e97                         0            <null>                                                             true      true            22         
+parts                                                              pg_catalog                                                         pg_namespace                                                       Table                                                              <null>                                                             false       false            mmuid:6609866a-3d7b-4f4b-95fe-ebfac769d699                         0            <null>                                                             true      false           18         
+parts                                                              pg_catalog                                                         pg_proc                                                            Table                                                              <null>                                                             false       false            mmuid:da4b747e-7d87-403a-8309-2cdf1399031b                         0            <null>                                                             true      true            24         
+parts                                                              pg_catalog                                                         pg_trigger                                                         Table                                                              <null>                                                             false       false            mmuid:9569efdb-21b2-4b4f-a2db-e7406267b8ed                         0            <null>                                                             true      false           25         
+parts                                                              pg_catalog                                                         pg_type                                                            Table                                                              <null>                                                             false       false            mmuid:9462e3f8-cd3c-414f-a570-f6f33c40e36a                         0            <null>                                                             true      false           21         
+parts                                                              pg_catalog                                                         pg_user                                                            Table                                                              <null>                                                             false       false            mmuid:28d034eb-6f39-402f-b642-9c9560e57247                         0            <null>                                                             true      false           28         
+Row Count : 29
+getColumnName    getColumnType  getCatalogName  getColumnClassName  getColumnLabel   getColumnTypeName  getSchemaName  getTableName  getColumnDisplaySize  getPrecision  getScale  isAutoIncrement  isCaseSensitive  isCurrency  isDefinitelyWritable  isNullable  isReadOnly  isSearchable  isSigned  isWritable  
+vdbname          12                             java.lang.String    vdbname          varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+schemaname       12                             java.lang.String    schemaname       varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+name             12                             java.lang.String    name             varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+type             12                             java.lang.String    type             varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+nameinsource     12                             java.lang.String    nameinsource     varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+isphysical       -7                             java.lang.Boolean   isphysical       bool                                            1                     1             0         false            false            false       false                 2           false       true          false     true        
+supportsupdates  -7                             java.lang.Boolean   supportsupdates  bool                                            1                     1             0         false            false            false       false                 2           false       true          false     true        
+uid              12                             java.lang.String    uid              varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+cardinality      4                              java.lang.Integer   cardinality      int4                                            11                    10            0         false            false            false       false                 2           false       true          true      true        
+description      12                             java.lang.String    description      varchar                                         2147483647            0             0         false            true             false       false                 2           false       true          false     true        
+issystem         -7                             java.lang.Boolean   issystem         bool                                            1                     1             0         false            false            false       false                 2           false       true          false     true        
+ismaterialized   -7                             java.lang.Boolean   ismaterialized   bool                                            1                     1             0         false            false            false       false                 2           false       true          false     true        
+oid              4                              java.lang.Integer   oid              int4                                            11                    10            0         false            false            false       false                 2           false       true          true      true        



More information about the teiid-commits mailing list