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;
+
+@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