[teiid-commits] teiid SVN: r4472 - in trunk: api/src/main/java/org/teiid/translator and 17 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Tue Sep 25 18:15:12 EDT 2012


Author: rareddy
Date: 2012-09-25 18:15:11 -0400 (Tue, 25 Sep 2012)
New Revision: 4472

Added:
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCDirectQueryExecution.java
   trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/TestJDBCDirectQueryExecution.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectCreateUpdateDeleteQueryExecution.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectSearchQueryExecution.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPQueryExecution.java
   trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestLDAPDirectQueryExecution.java
   trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/execution/DirectQueryExecution.java
   trunk/connectors/translator-salesforce/src/test/java/org/teiid/translator/salesforce/execution/TestSalesForceDirectQueryExecution.java
   trunk/engine/src/main/java/org/teiid/query/metadata/DirectQueryMetadataRepository.java
Modified:
   trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java
   trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java
   trunk/api/src/test/java/org/teiid/translator/TestBaseDelegatingExecutionFactory.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionException.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionFactory.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCPlugin.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCProcedureExecution.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java
   trunk/connectors/translator-jdbc/src/main/resources/org/teiid/translator/jdbc/i18n.properties
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/IQueryToLdapSearchParser.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPExecutionFactory.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPPlugin.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSearchDetails.java
   trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSyncQueryExecution.java
   trunk/connectors/translator-ldap/src/main/resources/org/teiid/translator/ldap/i18n.properties
   trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestIQueryToLdapSearchParser.java
   trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapExecutionFactory.java
   trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapQueryExecution.java
   trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForceExecutionFactory.java
   trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForcePlugin.java
   trunk/connectors/translator-salesforce/src/main/resources/org/teiid/translator/salesforce/i18n.properties
   trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
   trunk/pom.xml
   trunk/runtime/src/main/java/org/teiid/runtime/AbstractVDBDeployer.java
   trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestExecutionReuse.java
Log:
TEIID-2176: Adding the native query procedures to JDBC, LDAP, Salesforce and OLAP translators.

Modified: trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java
===================================================================
--- trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -24,6 +24,7 @@
 
 import java.util.List;
 
+import org.teiid.language.Argument;
 import org.teiid.language.Call;
 import org.teiid.language.Command;
 import org.teiid.language.LanguageFactory;
@@ -451,4 +452,18 @@
 	public boolean supportsArrayType() {
 		return delegate.supportsArrayType();
 	}
+	@Override
+	public String getNativeQueryProcedureName() {
+		return delegate.getNativeQueryProcedureName();
+	}	
+	
+	public boolean supportsNativeQueries() {
+		return delegate.supportsNativeQueries();
+	}
+	@Override
+	public ResultSetExecution createDirectExecution(List<Argument> arguments,
+			Command command, ExecutionContext executionContext,
+			RuntimeMetadata metadata, C connection) throws TranslatorException {
+		 return delegate.createDirectExecution(arguments, command, executionContext, metadata, connection);
+	}	
 }

Modified: trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java
===================================================================
--- trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -33,6 +33,7 @@
 import org.teiid.connector.DataPlugin;
 import org.teiid.core.TeiidException;
 import org.teiid.core.util.ReflectionHelper;
+import org.teiid.language.Argument;
 import org.teiid.language.BatchedUpdates;
 import org.teiid.language.Call;
 import org.teiid.language.Command;
@@ -113,8 +114,9 @@
 	private int maxInSize = DEFAULT_MAX_IN_CRITERIA_SIZE;
 	private int maxDependentInPredicates = DEFAULT_MAX_IN_CRITERIA_SIZE;
 	private boolean copyLobs;
-	
+	private boolean supportsNativeQueries;
 	private LinkedList<FunctionMethod> pushdownFunctionMethods = new LinkedList<FunctionMethod>();
+	private String nativeProcedureName = "native"; //$NON-NLS-1$
 	
 	/**
 	 * Initialize the connector with supplied configuration
@@ -268,6 +270,13 @@
      * @return An execution object that can use to execute the command
      */
 	public Execution createExecution(Command command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
+		if (command instanceof Call) {
+			Call obj = (Call)command;
+			if (supportsNativeQueries() && obj.getMetadataObject().getName().equals(getNativeQueryProcedureName())) {
+				List<Argument> arguments = obj.getArguments();
+	    		return createDirectExecution(arguments, command, executionContext, metadata, connection);
+			}
+		}
 		if (command instanceof QueryExpression) {
 			return createResultSetExecution((QueryExpression)command, executionContext, metadata, connection);
 		}
@@ -292,6 +301,11 @@
 		 throw new TranslatorException(DataPlugin.Event.TEIID60001,  DataPlugin.Util.gs(DataPlugin.Event.TEIID60001, "createUpdateExecution")); //$NON-NLS-1$
 	}   
 	
+	@SuppressWarnings("unused")
+	public ResultSetExecution createDirectExecution(List<Argument> arguments, Command command, ExecutionContext executionContext, RuntimeMetadata metadata, C connection) throws TranslatorException {
+		 throw new TranslatorException(DataPlugin.Event.TEIID60001, DataPlugin.Util.gs(DataPlugin.Event.TEIID60001, "createDirectExecution")); //$NON-NLS-1$
+	}	
+	
     /** 
      * Support indicates connector can accept queries with SELECT DISTINCT
      * @since 3.1 SP2 
@@ -1035,5 +1049,31 @@
 	public boolean supportsArrayType() {
 		return false;
 	}
-
+	
+	/**
+	 * True, if this translator supports execution of source specific commands unaltered through 'native' procedure.
+	 * @return
+	 */
+	@TranslatorProperty(display="Supports Native Queries", description="True, if this translator supports execution of source specific commands unaltered through 'native' procedure", advanced=true)
+	public boolean supportsNativeQueries() {
+		return this.supportsNativeQueries;
+	}
+	
+	public void setSupportsNativeQueries(boolean state) {
+		this.supportsNativeQueries = state;
+	}
+	
+	/**
+	 * Defines the name of the procedure that need to be treated as "native" query processing procedure. This metadata or signature
+	 * of the procedure is defined automatically.
+	 * @return
+	 */
+	@TranslatorProperty(display="Name of the native query", description="The name of the procedure that is considered as the name of the direct query procedure", advanced=true)
+	public String getNativeQueryProcedureName() {
+		return this.nativeProcedureName;
+	}
+	
+	public void setNativeQueryProcedureName(String name) {
+		this.nativeProcedureName = name;
+	}	
 }

Modified: trunk/api/src/test/java/org/teiid/translator/TestBaseDelegatingExecutionFactory.java
===================================================================
--- trunk/api/src/test/java/org/teiid/translator/TestBaseDelegatingExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/api/src/test/java/org/teiid/translator/TestBaseDelegatingExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -34,7 +34,7 @@
 		Method[] methods = ExecutionFactory.class.getDeclaredMethods();
 		Method[] proxyMethods = BaseDelegatingExecutionFactory.class.getDeclaredMethods();
 		//excluding the setter methods the counts should be equal
-		assertEquals(methods.length - 10, proxyMethods.length);
+		assertEquals(methods.length - 12, proxyMethods.length);
 	}
 	
 }

Added: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCDirectQueryExecution.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCDirectQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCDirectQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,158 @@
+/*
+ * 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.translator.jdbc;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.teiid.language.Argument;
+import org.teiid.language.Command;
+import org.teiid.logging.LogConstants;
+import org.teiid.logging.LogManager;
+import org.teiid.translator.DataNotAvailableException;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.ProcedureExecution;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.TypeFacility;
+
+
+public class JDBCDirectQueryExecution extends JDBCQueryExecution implements ProcedureExecution {
+
+    protected int columnCount;
+    private List<Argument> arguments;
+    protected int updateCount = -1;
+
+    public JDBCDirectQueryExecution(List<Argument> arguments, Command command, Connection connection, ExecutionContext context, JDBCExecutionFactory env) {
+        super(command, connection, context, env);
+        this.arguments = arguments;
+    }
+    
+    @Override
+    public void execute() throws TranslatorException {
+    	String sourceSQL = (String) this.arguments.get(0).getArgumentValue().getValue();
+    	List<Argument> parameters = this.arguments.subList(1, this.arguments.size());
+    			
+        LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Source sql", sourceSQL); //$NON-NLS-1$
+        boolean prepared = (sourceSQL.indexOf('?') != -1);
+        boolean callable = (sourceSQL.indexOf("call ") != -1); //$NON-NLS-1$
+        int paramCount = getParamCount(sourceSQL);
+        
+        try {
+        	if (callable) {
+        		CallableStatement cstmt = getCallableStatement(sourceSQL);
+        		this.results = this.executionFactory.executeStoredProcedure(cstmt, parameters, TypeFacility.RUNTIME_TYPES.OBJECT);
+        		this.columnCount = this.results.getMetaData().getColumnCount();
+        	}
+        	else {
+            	Statement stmt;
+            	boolean hasResults = false;
+        	
+	        	if(prepared) {
+	            	PreparedStatement pstatement = getPreparedStatement(sourceSQL);
+	            	for (int i = 0; i < paramCount; i++) {
+	            		if (this.arguments.size()-1 < paramCount) {
+	            			throw new TranslatorException(JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID11019, sourceSQL));
+	            		}
+	            		Argument arg = this.arguments.get(i+1);
+	            		pstatement.setObject(i+1, arg.getArgumentValue().getValue());
+	            	}
+	                stmt = pstatement;
+	                hasResults = pstatement.execute();
+	            }
+	        	else {
+	        		stmt = getStatement();
+	        		hasResults = stmt.execute(sourceSQL);
+	        	}
+	    		
+	        	if (hasResults) {
+	    			this.results = stmt.getResultSet();
+	    			this.columnCount = this.results.getMetaData().getColumnCount();
+	    		}
+	    		else {
+	    			this.updateCount = stmt.getUpdateCount();
+	    		}
+        	}
+            addStatementWarnings();
+        } catch (SQLException e) {
+             throw new JDBCExecutionException(JDBCPlugin.Event.TEIID11008, e, sourceSQL);
+        }
+    }
+
+	private int getParamCount(String sourceSQL) {
+		int paramCount = 0;
+        int idx = -1;
+        while (true) {
+        	idx = sourceSQL.indexOf('?', idx+1);
+        	if (idx == -1) {
+        		break;
+        	}
+        	paramCount++;
+        }
+		return paramCount;
+	}
+
+    @Override
+    public List<?> next() throws TranslatorException, DataNotAvailableException {
+        try {
+        	ArrayList<Object[]> row = new ArrayList<Object[]>(1);
+        	
+        	if (this.results != null) {
+	            if (this.results.next()) {
+	                // New row for result set
+	                List<Object> vals = new ArrayList<Object>(this.columnCount);
+	
+	                for (int i = 0; i < this.columnCount; i++) {
+	                    // Convert from 0-based to 1-based
+	                    Object value = this.executionFactory.retrieveValue(this.results, i+1, TypeFacility.RUNTIME_TYPES.OBJECT);
+	                    vals.add(value); 
+	                }
+	                row.add(vals.toArray(new Object[vals.size()]));
+	                return row;
+	            } 
+        	}
+        	else if (this.updateCount != -1) {
+        		List<Object> vals = new ArrayList<Object>(1);
+        		vals.add(new Integer(this.updateCount));
+        		this.updateCount = -1;
+                row.add(vals.toArray(new Object[vals.size()]));
+                return row;
+        	}
+        } catch (SQLException e) {
+            throw new TranslatorException(e,JDBCPlugin.Util.getString("JDBCTranslator.Unexpected_exception_translating_results___8", e.getMessage())); //$NON-NLS-1$
+        }
+        return null;
+    }
+    
+	@Override
+	public List<?> getOutputParameterValues() throws TranslatorException {
+		return null;
+	}
+}


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

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionException.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionException.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionException.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -37,4 +37,9 @@
 		super(error, commands == null || commands.length == 0 ? event.toString()+":"+error.getMessage() : event.toString()+":"+JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID11004, Arrays.toString(commands))); //$NON-NLS-1$ //$NON-NLS-2$ 
 		setCode(String.valueOf(error.getErrorCode()));
 	}
+	
+	public JDBCExecutionException(BundleUtil.Event event, SQLException error, String command) {
+		super(error, event.toString()+":"+JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID11004, command)); //$NON-NLS-1$
+		setCode(String.valueOf(error.getErrorCode()));
+	}
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -140,6 +140,7 @@
 		setSupportsInnerJoins(true);
 		setMaxInCriteriaSize(DEFAULT_MAX_IN_CRITERIA);
 		setMaxDependentInPredicates(DEFAULT_MAX_DEPENDENT_PREDICATES);
+		setSupportsNativeQueries(true);
 	}
     
 	@Override
@@ -207,6 +208,14 @@
     }
     
     @Override
+    public ResultSetExecution createDirectExecution(List<Argument> arguments, Command command, ExecutionContext executionContext, RuntimeMetadata metadata, Connection conn)
+    		throws TranslatorException {
+    	//TODO: This is not correct; this should be only called once for connection creation    	
+    	obtainedConnection(conn);
+    	return new JDBCDirectQueryExecution(arguments, command, conn, executionContext, this);
+    }    
+    
+    @Override
     public ProcedureExecution createProcedureExecution(Call command, ExecutionContext executionContext, RuntimeMetadata metadata, Connection conn)
     		throws TranslatorException {
 		//TODO: This is not correct; this should be only called once for connection creation    	
@@ -717,15 +726,14 @@
      * stored procedures differently, subclasses should override this method
      * if necessary.
      */
-    public ResultSet executeStoredProcedure(CallableStatement statement, TranslatedCommand command, Class<?> returnType) throws SQLException {
-        List params = command.getPreparedValues();
+    public ResultSet executeStoredProcedure(CallableStatement statement, List<Argument> preparedValues, Class<?> returnType) throws SQLException {
         int index = 1;
         
         if(returnType != null){
             registerSpecificTypeOfOutParameter(statement, returnType, index++);
         }
         
-        Iterator iter = params.iterator();
+        Iterator iter = preparedValues.iterator();
         while(iter.hasNext()){
             Argument param = (Argument)iter.next();
                     

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCPlugin.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCPlugin.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCPlugin.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -54,5 +54,6 @@
 		TEIID11016,
 		TEIID11017,
 		TEIID11018,
+		TEIID11019
 	}
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCProcedureExecution.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCProcedureExecution.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCProcedureExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -64,7 +64,7 @@
         try{
             //create parameter index map
             CallableStatement cstmt = getCallableStatement(sql);
-            this.results = this.executionFactory.executeStoredProcedure(cstmt, translatedComm, procedure.getReturnType());
+            this.results = this.executionFactory.executeStoredProcedure(cstmt, translatedComm.getPreparedValues(), procedure.getReturnType());
             addStatementWarnings();
         }catch(SQLException e){
              throw new TranslatorException(JDBCPlugin.Event.TEIID11004, e, JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID11004, sql));

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -730,8 +730,8 @@
     
     @Override
     public ResultSet executeStoredProcedure(CallableStatement statement,
-    		TranslatedCommand command, Class<?> returnType) throws SQLException {
-    	ResultSet rs = super.executeStoredProcedure(statement, command, returnType);
+    		List<Argument> preparedValues, Class<?> returnType) throws SQLException {
+    	ResultSet rs = super.executeStoredProcedure(statement, preparedValues, returnType);
     	if (!oracleSuppliedDriver || returnType != RefCursorType.class) {
     		return rs;
     	}

Modified: trunk/connectors/translator-jdbc/src/main/resources/org/teiid/translator/jdbc/i18n.properties
===================================================================
--- trunk/connectors/translator-jdbc/src/main/resources/org/teiid/translator/jdbc/i18n.properties	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-jdbc/src/main/resources/org/teiid/translator/jdbc/i18n.properties	2012-09-25 22:15:11 UTC (rev 4472)
@@ -32,4 +32,5 @@
 TEIID11002=Failed to report the JDBC driver and connection information
 TEIID11006=Teiid runtime names, which are case insensitive, for the imported metadata are not unique.  If not already set, use the setting importer.useFullSchemaName to create Teiid names that include the source schema.
 TEIID11017=Invalid name in source sequence format.  Expected <element name> {0} <sequence name>.<sequence value>, but was {1}
-TEIID11018=Connection is null; Datasource may not have been defined. Requires a active connection to retrieve the metadata.
\ No newline at end of file
+TEIID11018=Connection is null; Datasource may not have been defined. Requires a active connection to retrieve the metadata.
+TEIID11019=For direct JDBC execution of command "{0}", not any/all parameters are supplied for the prepared jdbc call.
\ No newline at end of file

Added: trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/TestJDBCDirectQueryExecution.java
===================================================================
--- trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/TestJDBCDirectQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/TestJDBCDirectQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,136 @@
+/*
+ * 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.translator.jdbc;
+
+import static org.junit.Assert.*;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.teiid.language.Command;
+import org.teiid.metadata.RuntimeMetadata;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.ResultSetExecution;
+
+ at SuppressWarnings("nls")
+public class TestJDBCDirectQueryExecution {
+	
+	@Test public void testProcedureExecution() throws Exception {
+		Command command = TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "exec native('{?=call spTest8a()}')"); //$NON-NLS-1$
+		Connection connection = Mockito.mock(Connection.class);
+		CallableStatement cs = Mockito.mock(CallableStatement.class);
+		ResultSet rs = Mockito.mock(ResultSet.class);
+		ResultSetMetaData rsm = Mockito.mock(ResultSetMetaData.class);
+		
+		Mockito.stub(cs.getUpdateCount()).toReturn(-1);
+		Mockito.stub(cs.getResultSet()).toReturn(rs);
+		Mockito.stub(rs.getMetaData()).toReturn(rsm);
+		Mockito.stub(rsm.getColumnCount()).toReturn(1);
+		Mockito.stub(connection.prepareCall("{?=call spTest8a()}")).toReturn(cs); //$NON-NLS-1$
+		Mockito.stub(rs.next()).toReturn(true);
+		Mockito.stub(rs.getObject(1)).toReturn(5);
+		Mockito.stub(connection.getMetaData()).toReturn(Mockito.mock(DatabaseMetaData.class));
+		
+		JDBCExecutionFactory ef = new JDBCExecutionFactory();
+		ResultSetExecution execution = (ResultSetExecution)ef.createExecution(command,  Mockito.mock(ExecutionContext.class), Mockito.mock(RuntimeMetadata.class), connection);
+		execution.execute();
+		assertArrayEquals(new Object[] {5}, (Object[])execution.next().get(0));
+	}
+	
+	@Test public void testSelectExecution() throws Exception {
+		Command command = TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "call native('select * from Source')"); //$NON-NLS-1$
+		Connection connection = Mockito.mock(Connection.class);
+		Statement stmt = Mockito.mock(Statement.class);
+		ResultSet rs = Mockito.mock(ResultSet.class);
+		ResultSetMetaData rsm = Mockito.mock(ResultSetMetaData.class);
+		
+		Mockito.stub(stmt.getUpdateCount()).toReturn(-1);
+		Mockito.stub(stmt.getResultSet()).toReturn(rs);
+		Mockito.stub(rs.getMetaData()).toReturn(rsm);
+		Mockito.stub(rsm.getColumnCount()).toReturn(2);
+		Mockito.stub(connection.createStatement()).toReturn(stmt); //$NON-NLS-1$
+		Mockito.stub(stmt.execute("select * from Source")).toReturn(true);
+		Mockito.stub(rs.next()).toReturn(true);
+		Mockito.stub(rs.getObject(1)).toReturn(5);
+		Mockito.stub(rs.getObject(2)).toReturn("five");
+		Mockito.stub(connection.getMetaData()).toReturn(Mockito.mock(DatabaseMetaData.class));
+		
+		JDBCExecutionFactory ef = new JDBCExecutionFactory();
+		ResultSetExecution execution = (ResultSetExecution)ef.createExecution(command,  Mockito.mock(ExecutionContext.class), Mockito.mock(RuntimeMetadata.class), connection);
+		execution.execute();
+		assertArrayEquals(new Object[] {5, "five"}, (Object[])execution.next().get(0));
+	}
+
+	@Test public void testPrepareExecution() throws Exception {
+		Command command = TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "call native('select * from Source where e1 = ?', 2)"); //$NON-NLS-1$
+		Connection connection = Mockito.mock(Connection.class);
+		PreparedStatement stmt = Mockito.mock(PreparedStatement.class);
+		ResultSet rs = Mockito.mock(ResultSet.class);
+		ResultSetMetaData rsm = Mockito.mock(ResultSetMetaData.class);
+		
+		Mockito.stub(stmt.getUpdateCount()).toReturn(-1);
+		Mockito.stub(stmt.getResultSet()).toReturn(rs);
+		Mockito.stub(stmt.execute()).toReturn(true);
+		Mockito.stub(rs.getMetaData()).toReturn(rsm);
+		Mockito.stub(rsm.getColumnCount()).toReturn(2);
+		Mockito.stub(connection.prepareStatement("select * from Source where e1 = ?")).toReturn(stmt); //$NON-NLS-1$
+		Mockito.stub(rs.next()).toReturn(true);
+		Mockito.stub(rs.getObject(1)).toReturn(5);
+		Mockito.stub(rs.getObject(2)).toReturn("five");
+		Mockito.stub(connection.getMetaData()).toReturn(Mockito.mock(DatabaseMetaData.class));
+		
+		JDBCExecutionFactory ef = new JDBCExecutionFactory();
+		ResultSetExecution execution = (ResultSetExecution)ef.createExecution(command,  Mockito.mock(ExecutionContext.class), Mockito.mock(RuntimeMetadata.class), connection);
+		execution.execute();
+		assertArrayEquals(new Object[] {5, "five"}, (Object[])execution.next().get(0));
+	}
+	
+	@Test public void testPrepareUpdateCount() throws Exception {
+		Command command = TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "call native('update source set e1=? where e2 = ?', 2, 'foo')"); //$NON-NLS-1$
+		Connection connection = Mockito.mock(Connection.class);
+		PreparedStatement stmt = Mockito.mock(PreparedStatement.class);
+		ResultSet rs = Mockito.mock(ResultSet.class);
+		ResultSetMetaData rsm = Mockito.mock(ResultSetMetaData.class);
+		
+		Mockito.stub(stmt.getUpdateCount()).toReturn(-1);
+		Mockito.stub(stmt.getUpdateCount()).toReturn(5);
+		Mockito.stub(stmt.execute()).toReturn(false);
+		Mockito.stub(rs.getMetaData()).toReturn(rsm);
+		Mockito.stub(rsm.getColumnCount()).toReturn(2);
+		Mockito.stub(connection.prepareStatement("update source set e1=? where e2 = ?")).toReturn(stmt); //$NON-NLS-1$
+		Mockito.stub(connection.getMetaData()).toReturn(Mockito.mock(DatabaseMetaData.class));
+		
+		JDBCExecutionFactory ef = new JDBCExecutionFactory();
+		ResultSetExecution execution = (ResultSetExecution)ef.createExecution(command,  Mockito.mock(ExecutionContext.class), Mockito.mock(RuntimeMetadata.class), connection);
+		execution.execute();
+		assertArrayEquals(new Object[] {5}, (Object[])execution.next().get(0));
+	}	
+}


Property changes on: trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/TestJDBCDirectQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/IQueryToLdapSearchParser.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/IQueryToLdapSearchParser.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/IQueryToLdapSearchParser.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -41,32 +41,10 @@
 import java.util.LinkedList;
 import java.util.List;
 
-import javax.naming.NamingException;
-import javax.naming.directory.BasicAttribute;
 import javax.naming.directory.SearchControls;
 import javax.naming.ldap.SortKey;
 
-import org.teiid.language.AggregateFunction;
-import org.teiid.language.AndOr;
-import org.teiid.language.ColumnReference;
-import org.teiid.language.Comparison;
-import org.teiid.language.Condition;
-import org.teiid.language.DerivedColumn;
-import org.teiid.language.Exists;
-import org.teiid.language.Expression;
-import org.teiid.language.Function;
-import org.teiid.language.In;
-import org.teiid.language.Like;
-import org.teiid.language.Limit;
-import org.teiid.language.Literal;
-import org.teiid.language.NamedTable;
-import org.teiid.language.Not;
-import org.teiid.language.OrderBy;
-import org.teiid.language.ScalarSubquery;
-import org.teiid.language.SearchedCase;
-import org.teiid.language.Select;
-import org.teiid.language.SortSpecification;
-import org.teiid.language.TableReference;
+import org.teiid.language.*;
 import org.teiid.language.Comparison.Operator;
 import org.teiid.language.SortSpecification.Ordering;
 import org.teiid.logging.LogConstants;
@@ -113,7 +91,6 @@
 	public LDAPSearchDetails translateSQLQueryToLDAPSearch(Select query) throws TranslatorException {
 			// Parse SELECT symbols.
 			// The columns will be translated into LDAP attributes of interest.
-			ArrayList<BasicAttribute> attributeList = getAttributesFromSelectSymbols(query);
 			ArrayList<Column> elementList = getElementsFromSelectSymbols(query);
 			
 			// Parse FROM table.
@@ -165,14 +142,9 @@
 			}
 			
 			// Create Search Details
-			LDAPSearchDetails sd = new LDAPSearchDetails(contextName, searchScope, filterBuilder.toString(), attributeList, sortKeys, countLimit, elementList);
+			LDAPSearchDetails sd = new LDAPSearchDetails(contextName, searchScope, filterBuilder.toString(), sortKeys, countLimit, elementList);
 			// Search Details logging
-			try {
-				sd.printDetailsToLog();
-			} catch (NamingException nme) {
-				final String msg = LDAPPlugin.Util.getString("IQueryToLdapSearchParser.searchDetailsLoggingError");  //$NON-NLS-1$
-				throw new TranslatorException(msg);
-			}
+			sd.printDetailsToLog();
 			
 			return sd;
 			
@@ -588,7 +560,7 @@
     // GHH 20080326 - found that code to fall back on Name if NameInSource
 	// was null wasn't working properly, so replaced with tried and true
 	// code from another custom connector.
-	public String getNameFromElement(Column e) {
+	public static String getNameFromElement(Column e) {
 		String ldapAttributeName = null;
 		ldapAttributeName = e.getNameInSource();
 		if (ldapAttributeName == null || ldapAttributeName.equals("")) { //$NON-NLS-1$
@@ -614,28 +586,6 @@
 		return selectElementList;
 	}
 	
-	/** 
-	 * Method to get attribute list from the supplied query
-	 * @param query the supplied Query
-	 * @return the list of attributes
-	 */
-	private ArrayList<BasicAttribute> getAttributesFromSelectSymbols(Select query) {
-		ArrayList<BasicAttribute> ldapAttributeList = new ArrayList<BasicAttribute>();
-			
-		Iterator<DerivedColumn> selectSymbolItr = query.getDerivedColumns().iterator();
-		int i=0;
-		while(selectSymbolItr.hasNext()) {
-			Column e = getElementFromSymbol(selectSymbolItr.next());
-			String ldapAttributeName = this.getNameFromElement(e);
-			Object ldapAttributeClass = e.getJavaType();
-
-			// Store the element's name and class type, so that we know what to look for in the search results.
-			BasicAttribute newAttr = new BasicAttribute(ldapAttributeName, ldapAttributeClass);
-			ldapAttributeList.add(newAttr);
-			i++;
-		}
-		return ldapAttributeList;
-	}
 	
     /**
      * Helper method for getting runtime {@link org.teiid.connector.metadata.runtime.Element} from a

Added: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectCreateUpdateDeleteQueryExecution.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectCreateUpdateDeleteQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectCreateUpdateDeleteQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,190 @@
+/*
+ * 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.translator.ldap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.naming.NamingException;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.ldap.LdapContext;
+
+import org.teiid.language.Argument;
+import org.teiid.translator.DataNotAvailableException;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.ProcedureExecution;
+import org.teiid.translator.TranslatorException;
+
+public class LDAPDirectCreateUpdateDeleteQueryExecution implements ProcedureExecution {
+	private static final String ATTRIBUTES = "attributes"; //$NON-NLS-1$
+	private List<Argument> arguments;
+	protected LdapContext ldapConnection;
+	protected LDAPExecutionFactory executionFactory;
+	protected ExecutionContext executionContext;
+	private int updateCount = -1;
+	
+	public LDAPDirectCreateUpdateDeleteQueryExecution(List<Argument> arguments, LDAPExecutionFactory factory, ExecutionContext executionContext, LdapContext connection) {
+		this.arguments = arguments;
+		this.executionFactory = factory;
+		this.executionContext = executionContext;
+		this.ldapConnection = connection;
+	}
+	
+	@Override
+	public void execute() throws TranslatorException {
+		String query = (String)arguments.get(0).getArgumentValue().getValue();
+		String firstToken = null;
+		
+		StringTokenizer st = new StringTokenizer(query, ";"); //$NON-NLS-1$
+		if (st.hasMoreTokens()) {
+			firstToken = st.nextToken();
+			if (!firstToken.equalsIgnoreCase("create") && !firstToken.equalsIgnoreCase("update") && !firstToken.equalsIgnoreCase("delete")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				throw new TranslatorException(LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12009));
+			}
+		}
+		
+		LdapContext ldapCtx = null;
+		try {
+			ldapCtx = (LdapContext)this.ldapConnection.lookup("");  //$NON-NLS-1$
+		} catch (NamingException ne) {
+			throw new TranslatorException(LDAPPlugin.Util.getString("LDAPUpdateExecution.createContextError",ne.getExplanation()));//$NON-NLS-1$
+		}		
+
+		if (firstToken.equalsIgnoreCase("delete")) { // //$NON-NLS-1$
+			String theDN = getDN(st); // the token after the marker is always DN
+			try {
+				ldapCtx.destroySubcontext(theDN);
+				this.updateCount = 1;
+			} catch (NamingException ne) {
+				throw new TranslatorException(LDAPPlugin.Util.getString("LDAPUpdateExecution.deleteFailed",theDN,ne.getExplanation()));//$NON-NLS-1$
+			} catch (Exception e) {
+				throw new TranslatorException(e, LDAPPlugin.Util.getString("LDAPUpdateExecution.deleteFailedUnexpected",theDN));//$NON-NLS-1$
+			}			
+		}
+		else if (firstToken.equalsIgnoreCase("create")) { //$NON-NLS-1$
+			String theDN = getDN(st); // the token after the marker is always DN
+			ArrayList<BasicAttribute> attributes = getAttributes(st, this.arguments);
+			BasicAttributes attrs = new BasicAttributes();
+			for (BasicAttribute ba:attributes) {
+				attrs.put(ba);
+			}
+			try {
+				ldapCtx.createSubcontext(theDN, attrs);
+				this.updateCount = 1;
+			} catch (NamingException ne) {
+				throw new TranslatorException(LDAPPlugin.Util.getString("LDAPUpdateExecution.insertFailed", theDN, ne.getExplanation()));//$NON-NLS-1$
+			} catch (Exception e) {
+				throw new TranslatorException(e,LDAPPlugin.Util.getString("LDAPUpdateExecution.insertFailedUnexpected", theDN));//$NON-NLS-1$
+			}			
+		}
+		else if (firstToken.equalsIgnoreCase("update")) { //$NON-NLS-1$
+			String theDN = getDN(st); // the token after the marker is always DN
+			ArrayList<BasicAttribute> attributes = getAttributes(st, this.arguments);
+			ModificationItem[] updateMods = new ModificationItem[attributes.size()];
+			int i=0;
+			for (BasicAttribute ba:attributes) {
+				updateMods[i++] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, ba);
+			}		
+			try {
+				ldapCtx.modifyAttributes(theDN, updateMods);
+				this.updateCount = 1;
+			} catch (NamingException ne) {
+				throw new TranslatorException(LDAPPlugin.Util.getString("LDAPUpdateExecution.updateFailed", theDN, ne.getExplanation()));//$NON-NLS-1$
+			} catch (Exception e) {
+				throw new TranslatorException(e, LDAPPlugin.Util.getString("LDAPUpdateExecution.updateFailedUnexpected",theDN));//$NON-NLS-1$
+			}			
+		}
+		
+	}
+	
+	private String getDN(StringTokenizer st) throws TranslatorException {
+		if (!st.hasMoreTokens()) {
+			throw new TranslatorException(LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12010));
+		}
+		return st.nextToken();
+	}
+
+	private ArrayList<BasicAttribute> getAttributes(StringTokenizer st, List<Argument> arguments) throws TranslatorException {
+		if (!st.hasMoreTokens()) {
+			throw new TranslatorException(LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12011));
+		}
+		
+		ArrayList<BasicAttribute> attributes = new ArrayList<BasicAttribute>();
+		
+		while(st.hasMoreElements()) {
+			String var = st.nextToken();
+			
+			int index = var.indexOf('=');
+			if (index == -1) {
+				continue;
+			}
+			String key = var.substring(0, index).trim().toLowerCase();
+			String value = var.substring(index+1).trim();
+			
+			if (key.equalsIgnoreCase(ATTRIBUTES)) {
+				StringTokenizer attrTokens = new StringTokenizer(value, ","); //$NON-NLS-1$
+				int attrCount = 1;
+				while(attrTokens.hasMoreElements()) {
+					String name = attrTokens.nextToken().trim();
+					if (arguments.size() <= attrCount) {
+						throw new TranslatorException(LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12012, name));
+					}
+					Argument argument = arguments.get(attrCount++);
+					Object  anObj = argument.getArgumentValue().getValue();
+					attributes.add(new BasicAttribute(name, anObj));
+				}
+				
+			}
+		}
+		return attributes;
+	}
+
+	@Override
+	public List<?> getOutputParameterValues() throws TranslatorException {
+		return null;
+	}
+
+	@Override
+	public List<?> next() throws TranslatorException, DataNotAvailableException {
+		if (this.updateCount != -1) {
+			Object[] columns = new Object[1];
+			columns[0] = this.updateCount;
+			List<Object[]> row = new ArrayList<Object[]>(1);
+			row.add(columns);
+			this.updateCount = -1;
+			return row;
+		}
+		return null;
+	}
+
+	@Override
+	public void close() {
+	}
+
+	@Override
+	public void cancel() throws TranslatorException {
+	}
+}


Property changes on: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectCreateUpdateDeleteQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectSearchQueryExecution.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectSearchQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectSearchQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,161 @@
+/*
+ * 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.translator.ldap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.naming.directory.SearchControls;
+import javax.naming.ldap.LdapContext;
+
+import org.teiid.language.Argument;
+import org.teiid.metadata.Column;
+import org.teiid.metadata.Datatype;
+import org.teiid.translator.DataNotAvailableException;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.ProcedureExecution;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.TypeFacility;
+
+public class LDAPDirectSearchQueryExecution extends LDAPSyncQueryExecution implements ProcedureExecution {
+
+	private static final String ATTRIBUTES = "attributes"; //$NON-NLS-1$
+	private static final String COUNT_LIMIT = "count-limit"; //$NON-NLS-1$
+	private static final String TIMEOUT = "timeout";//$NON-NLS-1$
+	private static final String SEARCH_SCOPE = "search-scope";//$NON-NLS-1$
+	private static final String CRITERIA = "filter";//$NON-NLS-1$
+	private static final String CONTEXT_NAME = "context-name";//$NON-NLS-1$
+	
+	private List<Argument> arguments;
+	
+	public LDAPDirectSearchQueryExecution(List<Argument> arguments, LDAPExecutionFactory factory, ExecutionContext executionContext, LdapContext connection) {
+		super(null, factory, executionContext, connection);
+		this.arguments = arguments;
+	}
+	
+	@Override
+	public void execute() throws TranslatorException {
+		this.delegate = buildRequest();
+		this.delegate.execute();		
+	}
+
+	private LDAPQueryExecution buildRequest() throws TranslatorException {
+		String query = (String)arguments.get(0).getArgumentValue().getValue();
+		
+		ArrayList<String> attributes = new ArrayList<String>();
+		ArrayList<Column> columns = new ArrayList<Column>();
+		String contextName = null;
+		String criteria = ""; //$NON-NLS-1$
+		String searchScope = this.executionFactory.getSearchDefaultScope().name();
+		int timeLimit = 0;
+		long countLimit = 0;
+		
+		StringTokenizer st = new StringTokenizer(query, ";"); //$NON-NLS-1$
+		while (st.hasMoreTokens()) {
+			String var = st.nextToken();
+			int index = var.indexOf('=');
+			if (index == -1) {
+				continue;
+			}
+			String key = var.substring(0, index).trim().toLowerCase();
+			String value = var.substring(index+1).trim();
+			
+			if (key.equalsIgnoreCase(CONTEXT_NAME)) {
+				contextName = value;
+			}
+			else if (key.equalsIgnoreCase(CRITERIA)) {
+				criteria = value;
+			}
+			else if (key.equalsIgnoreCase(SEARCH_SCOPE)) {
+				searchScope = value;
+			}
+			else if (key.equalsIgnoreCase(TIMEOUT)) {
+				timeLimit = Integer.parseInt(value);
+			}
+			else if (key.equalsIgnoreCase(COUNT_LIMIT)) {
+				countLimit = Long.parseLong(value);
+			}
+			else if (key.equalsIgnoreCase(ATTRIBUTES)) {
+				StringTokenizer attrTokens = new StringTokenizer(value, ","); //$NON-NLS-1$
+				while(attrTokens.hasMoreElements()) {
+					String name = attrTokens.nextToken().trim();
+					attributes.add(name);
+					
+					Column column = new Column();
+					column.setName(name);
+					Datatype type = new Datatype();
+					type.setName(TypeFacility.RUNTIME_NAMES.OBJECT);
+					type.setJavaClassName(Object.class.getCanonicalName());
+					column.setDatatype(type, true);
+					columns.add(column);
+				}
+			}
+		}
+		
+		int searchScopeInt = buildSearchScope(searchScope);
+		
+		// build search controls
+		SearchControls controls = new SearchControls();
+		controls.setSearchScope(searchScopeInt);
+		controls.setTimeLimit(timeLimit);
+		controls.setCountLimit(countLimit);
+		controls.setReturningAttributes(attributes.toArray(new String[attributes.size()]));
+		
+		LDAPSearchDetails searchDetails = new LDAPSearchDetails(contextName, searchScopeInt, criteria, null, countLimit,  columns);
+
+		// Create and configure the new search context.
+		LdapContext context =  createSearchContext(contextName);
+		return new LDAPQueryExecution(context, searchDetails, controls, this.executionFactory, this.executionContext);
+	}
+
+	private int buildSearchScope(String searchScope) {
+		int searchScopeInt = 0;
+		// this could be one of OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE
+		if (searchScope.equalsIgnoreCase("OBJECT_SCOPE")) { //$NON-NLS-1$
+			searchScopeInt = SearchControls.OBJECT_SCOPE;
+		}
+		else if (searchScope.equalsIgnoreCase("ONELEVEL_SCOPE")) {//$NON-NLS-1$
+			searchScopeInt = SearchControls.ONELEVEL_SCOPE;
+		}
+		else if (searchScope.equalsIgnoreCase("SUBTREE_SCOPE")) {//$NON-NLS-1$
+			searchScopeInt =  SearchControls.SUBTREE_SCOPE;
+		}
+		return searchScopeInt;
+	}
+
+	@Override
+	public List<?> next() throws TranslatorException, DataNotAvailableException {
+		List<?> vals = super.next();
+		if (vals == null) {
+			return null;
+		}
+		List<Object[]> row = new ArrayList<Object[]>(1);
+		row.add(vals.toArray(new Object[vals.size()]));
+		return row;
+	}
+	
+	@Override
+	public List<?> getOutputParameterValues() throws TranslatorException {
+		return null;
+	}
+}


Property changes on: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPDirectSearchQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPExecutionFactory.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -21,9 +21,12 @@
  */
 package org.teiid.translator.ldap;
 
+import java.util.List;
+
 import javax.naming.ldap.LdapContext;
 import javax.resource.cci.ConnectionFactory;
 
+import org.teiid.language.Argument;
 import org.teiid.language.Command;
 import org.teiid.language.QueryExpression;
 import org.teiid.language.Select;
@@ -59,6 +62,7 @@
 	public LDAPExecutionFactory() {
 		this.setMaxInCriteriaSize(1000);
 		this.setMaxDependentInPredicates(25); //no spec limit on query size, AD is 10MB for the query
+		setSupportsNativeQueries(true);
 	}
 	
     @TranslatorProperty(display="Default Search Base DN", description="Default Base DN for LDAP Searches")
@@ -101,6 +105,15 @@
 	}	
 	
 	@Override
+	public ResultSetExecution createDirectExecution(List<Argument> arguments,Command command, ExecutionContext executionContext,RuntimeMetadata metadata, LdapContext context) throws TranslatorException {
+		String query = (String) arguments.get(0).getArgumentValue().getValue();
+		if (query.startsWith("search;")) { //$NON-NLS-1$
+			return new LDAPDirectSearchQueryExecution(arguments, this, executionContext, context);
+		}
+		return new LDAPDirectCreateUpdateDeleteQueryExecution(arguments, this, executionContext, context);
+	}	
+	
+	@Override
     public boolean supportsCompareCriteriaEquals() {
 		return true;
 	}

Modified: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPPlugin.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPPlugin.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPPlugin.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -46,6 +46,10 @@
     	TEIID12005,
     	TEIID12006,
     	TEIID12007,
-    	TEIID12008
+    	TEIID12008,
+    	TEIID12009,
+    	TEIID12010,
+    	TEIID12011,
+    	TEIID12012,
     }
 }

Added: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPQueryExecution.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+
+/**
+ * 
+ * Please see the user's guide for a full description of capabilties, etc.
+ * 
+ * Description/Assumptions:
+ * 1. Table's name in source defines the base DN (or context) for the search.
+ * Example: Table.NameInSource=ou=people,dc=gene,dc=com
+ * [Optional] The table's name in source can also define a search scope. Append
+ * a "?" character as a delimiter to the base DN, and add the search scope string. 
+ * The following scopes are available:
+ * SUBTREE_SCOPE
+ * ONELEVEL_SCOPE
+ * OBJECT_SCOPE
+ * [Default] LDAPConnectorConstants.ldapDefaultSearchScope 
+ * is the default scope used, if no scope is defined (currently, ONELEVEL_SCOPE).
+ * 
+ * 2. Column's name in source defines the LDAP attribute name.
+ * [Default] If no name in source is defined, then we attempt to use the column name
+ * as the LDAP attribute name.
+ * 
+ * 
+ * TODO: Implement paged searches -- the LDAP server must support VirtualListViews.
+ * TODO: Implement cancel.
+ * TODO: Add Sun/Netscape implementation, AD/OpenLDAP implementation.
+ * 
+ * 
+ * Note: 
+ * Greater than is treated as >=
+ * Less-than is treater as <=
+ * If an LDAP entry has more than one entry for an attribute of interest (e.g. a select item), we only return the
+ * first occurrance. The first occurance is not predictably the same each time, either, according to the LDAP spec.
+ * If an attribute is not present, we return the empty string. Arguably, we could throw an exception.
+ * 
+ * Sun LDAP won't support Sort Orders for very large datasets. So, we've set the sorting to NONCRITICAL, which
+ * allows Sun to ignore the sort order. This will result in the results to come back as unsorted, without any error.
+ * 
+ * Removed support for ORDER BY for two reasons:
+ * 1: LDAP appears to have a limit to the number of records that 
+ * can be server-side sorted. When the limit is reached, two things can happen:
+ * a. If sortControl is set to CRITICAL, then the search fails.
+ * b. If sortControl is NONCRITICAL, then the search returns, unsorted.
+ * We'd like to support ORDER BY, no matter how large the size, so we turn it off,
+ * and allow MetaMatrix to do it for us.
+ * 2: Supporting ORDER BY appears to negatively effect the query plan
+ * when cost analysis is used. We stop using dependent queries, and start
+ * using inner joins.
+ *
+ */
+
+package org.teiid.translator.ldap;
+
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.SizeLimitExceededException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.PagedResultsControl;
+import javax.naming.ldap.PagedResultsResponseControl;
+import javax.naming.ldap.SortControl;
+import javax.naming.ldap.SortKey;
+
+import org.teiid.logging.LogConstants;
+import org.teiid.logging.LogManager;
+import org.teiid.metadata.Column;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.ResultSetExecution;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.TypeFacility;
+
+
+
+/** 
+ * LDAPSyncQueryExecution is responsible for executing an LDAP search 
+ * corresponding to a read-only "select" query from MetaMatrix.
+ */
+public class LDAPQueryExecution implements ResultSetExecution {
+
+	private static final String delimiter = "?"; //$NON-NLS-1$
+	
+	private LDAPSearchDetails searchDetails;
+	private LdapContext ldapCtx;
+	private NamingEnumeration<?> searchEnumeration;
+	private LDAPExecutionFactory executionFactory;
+	private ExecutionContext executionContext;
+	private SearchControls ctrls;
+	private int resultCount;
+
+	/** 
+	 * Constructor
+	 * @param executionMode the execution mode.
+	 * @param ctx the execution context.
+	 * @param logger the ConnectorLogger
+	 * @param connection the LDAP Context
+	 */
+	public LDAPQueryExecution(LdapContext ldapContext,LDAPSearchDetails search, SearchControls searchControls, LDAPExecutionFactory factory,ExecutionContext context) {
+		this.searchDetails = search;
+		this.ldapCtx = ldapContext;
+		this.ctrls = searchControls;
+		this.executionFactory = factory;
+		this.executionContext = context;
+	}
+
+	/** 
+	 * method to execute the supplied query
+	 * @param query the query object.
+	 * @param maxBatchSize the max batch size.
+	 */
+	@Override
+	public void execute() throws TranslatorException {
+		String ctxName = this.searchDetails.getContextName();
+		String filter = this.searchDetails.getContextFilter();
+		if (ctxName == null || filter == null || this.ctrls == null) {
+			throw new TranslatorException("Search context, filter, or controls were null. Cannot execute search."); //$NON-NLS-1$
+		}
+		setRequestControls(null);
+		// Execute the search.
+		executeSearch();
+	}
+
+	/** 
+	 * Set the standard request controls
+	 */
+	private void setRequestControls(byte[] cookie) throws TranslatorException {
+		List<Control> ctrl = new ArrayList<Control>();
+		SortKey[] keys = searchDetails.getSortKeys();
+		try {			
+			if (keys != null) {
+				ctrl.add(new SortControl(keys, Control.NONCRITICAL));
+			}
+			if (this.executionFactory.usePagination()) {
+				ctrl.add(new PagedResultsControl(this.executionContext.getBatchSize(), cookie, Control.CRITICAL));
+			}
+			if (!ctrl.isEmpty()) {
+				this.ldapCtx.setRequestControls(ctrl.toArray(new Control[ctrl.size()]));
+				LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Sort/pagination controls were created successfully."); //$NON-NLS-1$
+			}
+		} catch (NamingException ne) {
+            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.setControlsError") +  //$NON-NLS-1$
+            " : "+ne.getExplanation(); //$NON-NLS-1$
+			throw new TranslatorException(ne, msg);
+		} catch(IOException e) {
+			throw new TranslatorException(e);
+		}
+	}
+
+	/**
+	 * Perform the LDAP search against the subcontext, using the filter and 
+	 * search controls appropriate to the query and model metadata.
+	 */
+	private void executeSearch() throws TranslatorException {
+		String filter = searchDetails.getContextFilter();
+		try {
+			searchEnumeration = this.ldapCtx.search("", filter, ctrls); //$NON-NLS-1$
+		} catch (NamingException ne) {
+            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.execSearchError"); //$NON-NLS-1$
+			throw new TranslatorException(ne, msg + " : " + ne.getExplanation());  //$NON-NLS-1$ 
+		} catch(Exception e) {
+            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.execSearchError"); //$NON-NLS-1$
+			throw new TranslatorException(e, msg); 
+		}
+	}
+
+	// GHH 20080326 - attempt to implement cancel here.  First try to
+	// close the searchEnumeration, then the search context.
+	// We are very conservative when closing the enumeration
+	// but less so when closing context, since it is safe to call close
+	// on contexts multiple times
+	@Override
+	public void cancel() throws TranslatorException {
+		close();
+	}
+
+	// GHH 20080326 - replaced existing implementation with the same
+	// code as used by cancel method.  First try to
+	// close the searchEnumeration, then the search context
+	// We are very conservative when closing the enumeration
+	// but less so when closing context, since it is safe to call close
+	// on contexts multiple times
+	@Override
+	public void close() {
+		if (searchEnumeration != null) {
+			try {
+				searchEnumeration.close();
+			} catch (Exception e) { } // catch everything, because NamingEnumeration has undefined behavior if it previously hit an exception
+		}
+		if (ldapCtx != null) {
+			try {
+				ldapCtx.close();
+			} catch (NamingException ne) {
+	            LogManager.logWarning(LogConstants.CTX_CONNECTOR, LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12003, ne.getExplanation()));
+			}
+		}
+	}
+	
+	/**
+	 * Fetch the next batch of data from the LDAP searchEnumerationr result.
+	 * @return the next Batch of results.
+	 */
+	// GHH 20080326 - set all batches as last batch after an exception
+	// is thrown calling a method on the enumeration.  Per Javadoc for
+	// javax.naming.NamingEnumeration, enumeration is invalid after an
+	// exception is thrown - by setting last batch indicator we prevent
+	// it from being used again.
+	// GHH 20080326 - also added return of explanation for generic
+	// NamingException
+	public List<?> next() throws TranslatorException {
+		try {
+			// The search has been executed, so process up to one batch of
+			// results.
+			List<?> result = null;
+			while (result == null && searchEnumeration != null && searchEnumeration.hasMore())
+			{
+				SearchResult searchResult = (SearchResult) searchEnumeration.next();
+				result = getRow(searchResult);
+			}
+			
+			if (result == null && this.executionFactory.usePagination()) {
+			    byte[] cookie = null;
+				Control[] controls = ldapCtx.getResponseControls();
+		        if (controls != null) {
+		        	for (int i = 0; i < controls.length; i++) {
+		        		if (controls[i] instanceof PagedResultsResponseControl) {
+		        			PagedResultsResponseControl prrc = (PagedResultsResponseControl)controls[i];
+		                    cookie = prrc.getCookie();
+		        		}
+		        	}
+		        }
+		        
+		        if (cookie == null) {
+		        	return null;
+		        }
+	
+		        setRequestControls(cookie);
+		        executeSearch();
+		        return next();
+			}
+
+			if (result != null) {
+				resultCount++;
+			}
+			return result;
+		} catch (SizeLimitExceededException e) {
+			if (resultCount != searchDetails.getCountLimit()) {
+				String msg = LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12008);
+				TranslatorException te = new TranslatorException(e, msg);
+				if (executionFactory.isExceptionOnSizeLimitExceeded()) {
+					throw te;
+				}
+				this.executionContext.addWarning(te);
+				LogManager.logWarning(LogConstants.CTX_CONNECTOR, e, msg); 
+			}
+			return null; // GHH 20080326 - if size limit exceeded don't try to read more results
+		} catch (NamingException ne) {
+			throw new TranslatorException(ne, LDAPPlugin.Util.gs("ldap_error")); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Create a row using the searchResult and add it to the supplied batch.
+	 * @param batch the supplied batch
+	 * @param result the search result
+	 */
+	// GHH 20080326 - added fetching of DN of result, for directories that
+	// do not include it as an attribute
+	private List<?> getRow(SearchResult result) throws TranslatorException {
+		Attributes attrs = result.getAttributes();
+		String resultDN = result.getNameInNamespace(); // added GHH 20080326 
+		ArrayList<Column> attributeList = searchDetails.getElementList();
+		List<Object> row = new ArrayList<Object>(attributeList.size());
+		
+		for (Column col : attributeList) {
+			addResultToRow(col, resultDN, attrs, row);  // GHH 20080326 - added resultDN parameter to call
+		}
+		return row;
+	}
+
+	/**
+	 * Add Result to Row
+	 * @param modelElement the model element
+	 * @param attrs the attributes
+	 * @param row the row
+	 */
+	// GHH 20080326 - added resultDistinguishedName to method signature.  If
+	// there is an element in the model named "DN" and there is no attribute
+	// with this name in the search result, we return this new parameter
+	// value for that column in the result
+	// GHH 20080326 - added handling of ClassCastException when non-string
+	// attribute is returned
+	private void addResultToRow(Column modelElement, String resultDistinguishedName, Attributes attrs, List<Object> row) throws TranslatorException {
+
+		String strResult = null;
+		String modelAttrName = IQueryToLdapSearchParser.getNameFromElement(modelElement);
+		Class<?> modelAttrClass = modelElement.getJavaType();
+		
+		String multivalAttr = modelElement.getDefaultValue();
+		
+		if(modelAttrName == null) {
+            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.nullAttrError"); //$NON-NLS-1$
+			throw new TranslatorException(msg); 
+		}
+
+		Attribute resultAttr = attrs.get(modelAttrName);
+		
+		// If the attribute is not present, we return NULL.
+		if(resultAttr == null) {
+			// MPW - 2-20-07 - Changed from returning empty string to returning null.
+			//row.add("");
+			//logger.logTrace("Did not find a match for attribute named: " + modelAttrName);
+			// GHH 20080326 - return DN from input parameter
+			// if DN attribute is not present in search result
+			if (modelAttrName.toUpperCase().equals("DN")) {  //$NON-NLS-1$
+				row.add(resultDistinguishedName);
+			}
+			else {
+				row.add(null);
+			}
+			return;
+		}
+		Object objResult = null;
+		try {
+			if(TypeFacility.RUNTIME_TYPES.STRING.equals(modelAttrClass) && "multivalued-concat".equalsIgnoreCase(multivalAttr)) { //$NON-NLS-1$
+				// mpw 5/09
+				// Order the multi-valued attrs alphabetically before creating a single string, 
+				// using the delimiter to separate each token
+				ArrayList<String> multivalList = new ArrayList<String>();
+				NamingEnumeration<?> attrNE = resultAttr.getAll();
+				int length = 0;
+				while(attrNE.hasMore()) {
+					String val = (String)attrNE.next();
+					multivalList.add(val);
+					length += ((val==null?0:val.length()) + 1);
+				}
+				Collections.sort(multivalList);
+	
+				StringBuilder multivalSB = new StringBuilder(length);
+				Iterator<String> itr = multivalList.iterator();
+				while(itr.hasNext()) {
+					multivalSB.append(itr.next());
+					if (itr.hasNext()) {
+						multivalSB.append(delimiter);
+					}
+				}
+				row.add(multivalSB.toString());
+				return;
+			}
+			
+			//just a single value
+			objResult = resultAttr.get();
+		} catch (NamingException ne) {
+            final String msg = LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12004, modelAttrName) +" : "+ne.getExplanation(); //$NON-NLS-1$m
+            LogManager.logWarning(LogConstants.CTX_CONNECTOR, msg);
+			throw new TranslatorException(msg);
+		}
+
+		// GHH 20080326 - if attribute is not a string or empty, just
+		// return null.
+		// TODO - allow return of non-strings (always byte[]) as
+		// MM object (or blob).  Perhaps also add directory-specific logic
+		// to deserialize byte[] attributes into Java objects
+		// when appropriate
+		if (objResult instanceof String) {
+			strResult = (String)objResult;
+			// MPW - 3.9.07 - Also return NULL when attribute is unset or empty string.
+			// There is no way to differentiate between being unset and being the empty string.
+			if(strResult.equals("")) {  //$NON-NLS-1$
+				strResult = null;
+			}
+		}
+
+		// MPW: 3-11-07: Added support for java.lang.Integer conversion.
+		if(TypeFacility.RUNTIME_TYPES.TIMESTAMP.equals(modelAttrClass)) {
+			String timestampFormat = modelElement.getFormat();
+			if(timestampFormat == null) {
+				timestampFormat = LDAPConnectorConstants.ldapTimestampFormat;
+			}
+			SimpleDateFormat dateFormat = new SimpleDateFormat(timestampFormat);
+			try {
+				if(strResult != null) {
+					Date dateResult = dateFormat.parse(strResult);
+					Timestamp tsResult = new Timestamp(dateResult.getTime());
+					row.add(tsResult);
+				} else {
+					row.add(null);
+				}
+			} catch(ParseException pe) {
+				throw new TranslatorException(pe, LDAPPlugin.Util.getString("LDAPSyncQueryExecution.timestampParseFailed", modelAttrName)); //$NON-NLS-1$
+			}		
+			
+			//	TODO: Extend support for more types in the future.
+			// Specifically, add support for byte arrays, since that's actually supported
+			// in the underlying data source.
+		} else {
+			row.add(strResult); //the Teiid type conversion logic will handle refine from here if necessary
+		}
+	}
+	
+	// for testing.
+	LDAPSearchDetails getSearchDetails() {
+		return this.searchDetails;
+	}
+}


Property changes on: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSearchDetails.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSearchDetails.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSearchDetails.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -25,8 +25,6 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
 import javax.naming.directory.SearchControls;
 import javax.naming.ldap.SortKey;
 
@@ -45,7 +43,6 @@
 	private String contextName;
 	private int searchScope;
 	private String contextFilter;
-	private ArrayList attributeList;
 	private SortKey[] keys;
 //	private LdapSortKey[] netscapeKeys;
 	// If limit is set to -1, this means no limit (return all rows)
@@ -62,12 +59,11 @@
 	 * @param limit
 	 * @param elementList
 	 */
-	public LDAPSearchDetails(String name, int searchScope, String filter, ArrayList attributeList, SortKey[] keys, long limit, ArrayList elementList) {
+	public LDAPSearchDetails(String name, int searchScope, String filter, SortKey[] keys, long limit, ArrayList elementList) {
 
 		this.contextName = name;
 		this.searchScope = searchScope;
 		this.contextFilter = filter;
-		this.attributeList = attributeList;
 		this.keys = keys;
 		this.limit = limit;
 		this.elementList = elementList;
@@ -98,14 +94,6 @@
 	}
 	
 	/**
-	 * get the attribute list
-	 * @return the attribute list
-	 */
-	public ArrayList getAttributeList() {
-		return attributeList;
-	}
-	
-	/**
 	 * get the element list
 	 * @return the element list
 	 */
@@ -150,7 +138,7 @@
 	/**
 	 * Print Method for Logging - (Detail level logging)
 	 */
-	public void printDetailsToLog() throws NamingException {
+	public void printDetailsToLog() {
 		// Log Search Scope
 		LogManager.logDetail(LogConstants.CTX_CONNECTOR, "Search context: " + contextName); //$NON-NLS-1$
 		if(searchScope == SearchControls.SUBTREE_SCOPE) {
@@ -163,11 +151,12 @@
 		
 		// Log Search Attributes
 		LogManager.logDetail(LogConstants.CTX_CONNECTOR,"Search attributes: "); //$NON-NLS-1$	
-		Iterator itr = this.attributeList.iterator();
+		Iterator itr = this.elementList.iterator();
 		int i = 0;
 		while(itr.hasNext()) {
-			Attribute attr = (Attribute)itr.next();
-			LogManager.logDetail(LogConstants.CTX_CONNECTOR, "Attribute [" + i + "]: " + attr.getID() + " (" +attr.get().toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+			Column attr = (Column)itr.next();
+			String attrName = IQueryToLdapSearchParser.getNameFromElement(attr);
+			LogManager.logDetail(LogConstants.CTX_CONNECTOR, "Attribute [" + i + "]: " + attrName + " (" +attr.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 			i++;
 		}
 		

Modified: trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSyncQueryExecution.java
===================================================================
--- trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSyncQueryExecution.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/main/java/org/teiid/translator/ldap/LDAPSyncQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -71,69 +71,45 @@
 
 package org.teiid.translator.ldap;
 
-import java.io.IOException;
-import java.sql.Timestamp;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
 import java.util.List;
 
-import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
-import javax.naming.SizeLimitExceededException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
 import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.Control;
 import javax.naming.ldap.LdapContext;
-import javax.naming.ldap.PagedResultsControl;
-import javax.naming.ldap.PagedResultsResponseControl;
-import javax.naming.ldap.SortControl;
-import javax.naming.ldap.SortKey;
 
 import org.teiid.language.Select;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
 import org.teiid.metadata.Column;
+import org.teiid.translator.DataNotAvailableException;
 import org.teiid.translator.ExecutionContext;
 import org.teiid.translator.ResultSetExecution;
 import org.teiid.translator.TranslatorException;
-import org.teiid.translator.TypeFacility;
 
 
 
 /** 
  * LDAPSyncQueryExecution is responsible for executing an LDAP search 
- * corresponding to a read-only "select" query from MetaMatrix.
+ * corresponding to a read-only "select" query from Teiid.
  */
 public class LDAPSyncQueryExecution implements ResultSetExecution {
 
-	private static final String delimiter = "?"; //$NON-NLS-1$
-	
-	private LDAPSearchDetails searchDetails;
-	private LdapContext ldapConnection;
-	private LdapContext ldapCtx;
-	private NamingEnumeration<?> searchEnumeration;
-	private IQueryToLdapSearchParser parser;
+	protected LdapContext ldapConnection;
 	private Select query;
-	private LDAPExecutionFactory executionFactory;
-	private ExecutionContext executionContext;
-	private SearchControls ctrls;
-	private int resultCount;
-
+	protected LDAPExecutionFactory executionFactory;
+	protected ExecutionContext executionContext;
+	protected LDAPQueryExecution delegate;
+	
 	/** 
 	 * Constructor
 	 * @param executionMode the execution mode.
 	 * @param ctx the execution context.
 	 * @param logger the ConnectorLogger
-	 * @param ldapCtx the LDAP Context
+	 * @param connection the LDAP Context
 	 */
-	public LDAPSyncQueryExecution(Select query, LDAPExecutionFactory factory, ExecutionContext context, LdapContext ldapCtx) {
-		this.ldapConnection = ldapCtx;
+	public LDAPSyncQueryExecution(Select query, LDAPExecutionFactory factory, ExecutionContext context, LdapContext connection) {
+		this.ldapConnection = connection;
 		this.query = query;
 		this.executionFactory = factory;
 		this.executionContext = context;
@@ -147,76 +123,46 @@
 	@Override
 	public void execute() throws TranslatorException {
 		// Parse the IQuery, and translate it into an appropriate LDAP search.
-		this.parser = new IQueryToLdapSearchParser(this.executionFactory);
-		searchDetails = parser.translateSQLQueryToLDAPSearch(query);
+		IQueryToLdapSearchParser parser = new IQueryToLdapSearchParser(this.executionFactory);
+		LDAPSearchDetails searchDetails = parser.translateSQLQueryToLDAPSearch(query);
 
 		// Create and configure the new search context.
-		createSearchContext();
-		ctrls = setSearchControls();
-		String ctxName = searchDetails.getContextName();
-		String filter = searchDetails.getContextFilter();
-		if (ctxName == null || filter == null || ctrls == null) {
-			throw new TranslatorException("Search context, filter, or controls were null. Cannot execute search."); //$NON-NLS-1$
-		}
-		setRequestControls(null);
-		// Execute the search.
-		executeSearch();
+		LdapContext context =  createSearchContext(searchDetails.getContextName());
+		SearchControls ctrls = setSearchControls(searchDetails);
+		
+		this.delegate = new LDAPQueryExecution(context, searchDetails, ctrls, this.executionFactory, this.executionContext);
+		this.delegate.execute();
 	}
 
-	/** 
-	 * Set the standard request controls
-	 */
-	private void setRequestControls(byte[] cookie) throws TranslatorException {
-		List<Control> ctrl = new ArrayList<Control>();
-		SortKey[] keys = searchDetails.getSortKeys();
-		try {			
-			if (keys != null) {
-				ctrl.add(new SortControl(keys, Control.NONCRITICAL));
-			}
-			if (this.executionFactory.usePagination()) {
-				ctrl.add(new PagedResultsControl(this.executionContext.getBatchSize(), cookie, Control.CRITICAL));
-			}
-			if (!ctrl.isEmpty()) {
-				this.ldapCtx.setRequestControls(ctrl.toArray(new Control[ctrl.size()]));
-				LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Sort/pagination controls were created successfully."); //$NON-NLS-1$
-			}
-		} catch (NamingException ne) {
-            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.setControlsError") +  //$NON-NLS-1$
-            " : "+ne.getExplanation(); //$NON-NLS-1$
-			throw new TranslatorException(ne, msg);
-		} catch(IOException e) {
-			throw new TranslatorException(e);
-		}
-	}
 
+
 	/** 
 	 * Perform a lookup against the initial LDAP context, which 
 	 * sets the context to something appropriate for the search that is about to occur.
 	 * 
 	 */
-	private void createSearchContext() throws TranslatorException {
+	protected LdapContext createSearchContext(String contextName) throws TranslatorException {
 		try {
-			ldapCtx = (LdapContext) this.ldapConnection.lookup(searchDetails.getContextName());
+			return (LdapContext) this.ldapConnection.lookup(contextName);
 		} catch (NamingException ne) {			
-			if (searchDetails.getContextName() != null) {
-				LogManager.logError(LogConstants.CTX_CONNECTOR, LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12002, searchDetails.getContextName()));
+			if (contextName != null) {
+				LogManager.logError(LogConstants.CTX_CONNECTOR, LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12002, contextName));
 			}
             final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.createContextError"); //$NON-NLS-1$
 			throw new TranslatorException(msg); 
 		}
 	}
 
-
 	/** 
 	 * Set the search controls
 	 */
-	private SearchControls setSearchControls() {
+	private SearchControls setSearchControls(LDAPSearchDetails searchDetails) {
 		SearchControls ctrls = new SearchControls();
 		//ArrayList modelAttrList = searchDetails.getAttributeList();
 		ArrayList<Column> modelAttrList = searchDetails.getElementList();
 		String[] attrs = new String[modelAttrList.size()];
 		for (int i = 0; i < attrs.length; i++) {
-			attrs[i] = (parser.getNameFromElement(modelAttrList.get(i)));
+			attrs[i] = (IQueryToLdapSearchParser.getNameFromElement(modelAttrList.get(i)));
 		}
 
 		ctrls.setSearchScope(searchDetails.getSearchScope());
@@ -229,255 +175,23 @@
 		return ctrls;
 	}
 
-	/**
-	 * Perform the LDAP search against the subcontext, using the filter and 
-	 * search controls appropriate to the query and model metadata.
-	 */
-	private void executeSearch() throws TranslatorException {
-		String filter = searchDetails.getContextFilter();
-		try {
-			searchEnumeration = this.ldapCtx.search("", filter, ctrls); //$NON-NLS-1$
-		} catch (NamingException ne) {
-            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.execSearchError"); //$NON-NLS-1$
-			throw new TranslatorException(ne, msg + " : " + ne.getExplanation());  //$NON-NLS-1$ 
-		} catch(Exception e) {
-            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.execSearchError"); //$NON-NLS-1$
-			throw new TranslatorException(e, msg); 
-		}
+	@Override
+	public List<?> next() throws TranslatorException, DataNotAvailableException {
+		return this.delegate.next();
 	}
-
-	// GHH 20080326 - attempt to implement cancel here.  First try to
-	// close the searchEnumeration, then the search context.
-	// We are very conservative when closing the enumeration
-	// but less so when closing context, since it is safe to call close
-	// on contexts multiple times
+	
 	@Override
 	public void cancel() throws TranslatorException {
-		close();
+		this.delegate.cancel();
 	}
 
-	// GHH 20080326 - replaced existing implementation with the same
-	// code as used by cancel method.  First try to
-	// close the searchEnumeration, then the search context
-	// We are very conservative when closing the enumeration
-	// but less so when closing context, since it is safe to call close
-	// on contexts multiple times
 	@Override
 	public void close() {
-		if (searchEnumeration != null) {
-			try {
-				searchEnumeration.close();
-			} catch (Exception e) { } // catch everything, because NamingEnumeration has undefined behavior if it previously hit an exception
-		}
-		if (ldapCtx != null) {
-			try {
-				ldapCtx.close();
-			} catch (NamingException ne) {
-	            LogManager.logWarning(LogConstants.CTX_CONNECTOR, LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12003, ne.getExplanation()));
-			}
-		}
+		this.delegate.close();
 	}
 	
-	/**
-	 * Fetch the next batch of data from the LDAP searchEnumerationr result.
-	 * @return the next Batch of results.
-	 */
-	// GHH 20080326 - set all batches as last batch after an exception
-	// is thrown calling a method on the enumeration.  Per Javadoc for
-	// javax.naming.NamingEnumeration, enumeration is invalid after an
-	// exception is thrown - by setting last batch indicator we prevent
-	// it from being used again.
-	// GHH 20080326 - also added return of explanation for generic
-	// NamingException
-	public List<?> next() throws TranslatorException {
-		try {
-			// The search has been executed, so process up to one batch of
-			// results.
-			List<?> result = null;
-			while (result == null && searchEnumeration != null && searchEnumeration.hasMore())
-			{
-				SearchResult searchResult = (SearchResult) searchEnumeration.next();
-				result = getRow(searchResult);
-			}
-			
-			if (result == null && this.executionFactory.usePagination()) {
-			    byte[] cookie = null;
-				Control[] controls = ldapCtx.getResponseControls();
-		        if (controls != null) {
-		        	for (int i = 0; i < controls.length; i++) {
-		        		if (controls[i] instanceof PagedResultsResponseControl) {
-		        			PagedResultsResponseControl prrc = (PagedResultsResponseControl)controls[i];
-		                    cookie = prrc.getCookie();
-		        		}
-		        	}
-		        }
-		        
-		        if (cookie == null) {
-		        	return null;
-		        }
-	
-		        setRequestControls(cookie);
-		        executeSearch();
-		        return next();
-			}
-
-			if (result != null) {
-				resultCount++;
-			}
-			return result;
-		} catch (SizeLimitExceededException e) {
-			if (resultCount != searchDetails.getCountLimit()) {
-				String msg = LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12008);
-				TranslatorException te = new TranslatorException(e, msg);
-				if (executionFactory.isExceptionOnSizeLimitExceeded()) {
-					throw te;
-				}
-				this.executionContext.addWarning(te);
-				LogManager.logWarning(LogConstants.CTX_CONNECTOR, e, msg); 
-			}
-			return null; // GHH 20080326 - if size limit exceeded don't try to read more results
-		} catch (NamingException ne) {
-			throw new TranslatorException(ne, LDAPPlugin.Util.gs("ldap_error")); //$NON-NLS-1$
-		}
+	// testing
+	LDAPQueryExecution getDelegate() {
+		return this.delegate;
 	}
-
-	/**
-	 * Create a row using the searchResult and add it to the supplied batch.
-	 * @param batch the supplied batch
-	 * @param result the search result
-	 */
-	// GHH 20080326 - added fetching of DN of result, for directories that
-	// do not include it as an attribute
-	private List<?> getRow(SearchResult result) throws TranslatorException {
-		Attributes attrs = result.getAttributes();
-		String resultDN = result.getNameInNamespace(); // added GHH 20080326 
-		ArrayList<Column> attributeList = searchDetails.getElementList();
-		List<Object> row = new ArrayList<Object>(attributeList.size());
-		
-		for (Column col : attributeList) {
-			addResultToRow(col, resultDN, attrs, row);  // GHH 20080326 - added resultDN parameter to call
-		}
-		return row;
-	}
-
-	/**
-	 * Add Result to Row
-	 * @param modelElement the model element
-	 * @param attrs the attributes
-	 * @param row the row
-	 */
-	// GHH 20080326 - added resultDistinguishedName to method signature.  If
-	// there is an element in the model named "DN" and there is no attribute
-	// with this name in the search result, we return this new parameter
-	// value for that column in the result
-	// GHH 20080326 - added handling of ClassCastException when non-string
-	// attribute is returned
-	private void addResultToRow(Column modelElement, String resultDistinguishedName, Attributes attrs, List<Object> row) throws TranslatorException {
-
-		String strResult = null;
-		String modelAttrName = parser.getNameFromElement(modelElement);
-		Class<?> modelAttrClass = modelElement.getJavaType();
-		
-		String multivalAttr = modelElement.getDefaultValue();
-		
-		if(modelAttrName == null) {
-            final String msg = LDAPPlugin.Util.getString("LDAPSyncQueryExecution.nullAttrError"); //$NON-NLS-1$
-			throw new TranslatorException(msg); 
-		}
-
-		Attribute resultAttr = attrs.get(modelAttrName);
-		
-		// If the attribute is not present, we return NULL.
-		if(resultAttr == null) {
-			// MPW - 2-20-07 - Changed from returning empty string to returning null.
-			//row.add("");
-			//logger.logTrace("Did not find a match for attribute named: " + modelAttrName);
-			// GHH 20080326 - return DN from input parameter
-			// if DN attribute is not present in search result
-			if (modelAttrName.toUpperCase().equals("DN")) {  //$NON-NLS-1$
-				row.add(resultDistinguishedName);
-			}
-			else {
-				row.add(null);
-			}
-			return;
-		}
-		Object objResult = null;
-		try {
-			if(TypeFacility.RUNTIME_TYPES.STRING.equals(modelAttrClass) && "multivalued-concat".equalsIgnoreCase(multivalAttr)) { //$NON-NLS-1$
-				// mpw 5/09
-				// Order the multi-valued attrs alphabetically before creating a single string, 
-				// using the delimiter to separate each token
-				ArrayList<String> multivalList = new ArrayList<String>();
-				NamingEnumeration<?> attrNE = resultAttr.getAll();
-				int length = 0;
-				while(attrNE.hasMore()) {
-					String val = (String)attrNE.next();
-					multivalList.add(val);
-					length += ((val==null?0:val.length()) + 1);
-				}
-				Collections.sort(multivalList);
-	
-				StringBuilder multivalSB = new StringBuilder(length);
-				Iterator<String> itr = multivalList.iterator();
-				while(itr.hasNext()) {
-					multivalSB.append(itr.next());
-					if (itr.hasNext()) {
-						multivalSB.append(delimiter);
-					}
-				}
-				row.add(multivalSB.toString());
-				return;
-			}
-			
-			//just a single value
-			objResult = resultAttr.get();
-		} catch (NamingException ne) {
-            final String msg = LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12004, modelAttrName) +" : "+ne.getExplanation(); //$NON-NLS-1$m
-            LogManager.logWarning(LogConstants.CTX_CONNECTOR, msg);
-			throw new TranslatorException(msg);
-		}
-
-		// GHH 20080326 - if attribute is not a string or empty, just
-		// return null.
-		// TODO - allow return of non-strings (always byte[]) as
-		// MM object (or blob).  Perhaps also add directory-specific logic
-		// to deserialize byte[] attributes into Java objects
-		// when appropriate
-		if (objResult instanceof String) {
-			strResult = (String)objResult;
-			// MPW - 3.9.07 - Also return NULL when attribute is unset or empty string.
-			// There is no way to differentiate between being unset and being the empty string.
-			if(strResult.equals("")) {  //$NON-NLS-1$
-				strResult = null;
-			}
-		}
-
-		// MPW: 3-11-07: Added support for java.lang.Integer conversion.
-		if(TypeFacility.RUNTIME_TYPES.TIMESTAMP.equals(modelAttrClass)) {
-			String timestampFormat = modelElement.getFormat();
-			if(timestampFormat == null) {
-				timestampFormat = LDAPConnectorConstants.ldapTimestampFormat;
-			}
-			SimpleDateFormat dateFormat = new SimpleDateFormat(timestampFormat);
-			try {
-				if(strResult != null) {
-					Date dateResult = dateFormat.parse(strResult);
-					Timestamp tsResult = new Timestamp(dateResult.getTime());
-					row.add(tsResult);
-				} else {
-					row.add(null);
-				}
-			} catch(ParseException pe) {
-				throw new TranslatorException(pe, LDAPPlugin.Util.getString("LDAPSyncQueryExecution.timestampParseFailed", modelAttrName)); //$NON-NLS-1$
-			}		
-			
-			//	TODO: Extend support for more types in the future.
-			// Specifically, add support for byte arrays, since that's actually supported
-			// in the underlying data source.
-		} else {
-			row.add(strResult); //the Teiid type conversion logic will handle refine from here if necessary
-		}
-	}
-	
 }

Modified: trunk/connectors/translator-ldap/src/main/resources/org/teiid/translator/ldap/i18n.properties
===================================================================
--- trunk/connectors/translator-ldap/src/main/resources/org/teiid/translator/ldap/i18n.properties	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/main/resources/org/teiid/translator/ldap/i18n.properties	2012-09-25 22:15:11 UTC (rev 4472)
@@ -67,4 +67,8 @@
 TEIID12006=Received IScalarSubquery, but it is not supported. Check capabilties.
 TEIID12007=Received ISearchedCaseExpression, but it is not supported. Check capabilties.
 TEIID12002=Attempted to search context: {0}
-TEIID12008=LDAP Search results exceeded size limit. Results may be incomplete.
\ No newline at end of file
+TEIID12008=LDAP Search results exceeded size limit. Results may be incomplete.
+TEIID12009=Unknown LDAP Request; the query string must start with [search|create|update|delete]
+TEIID12010=The DN is not defined; DN should be the token after the marker tokens [search|create|update|delete]
+TEIID12011=attributes are not defined; use "attributes=..." form using the comma delimited to specify all the names.
+TEIID12012=create/update operation did not find the value for attribute {0}; Each attribute value is defined as the separate parameter in the procedure call.
\ No newline at end of file

Modified: trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestIQueryToLdapSearchParser.java
===================================================================
--- trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestIQueryToLdapSearchParser.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestIQueryToLdapSearchParser.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -27,7 +27,6 @@
 import java.util.Iterator;
 import java.util.List;
 
-import javax.naming.directory.Attribute;
 import javax.naming.directory.SearchControls;
 import javax.naming.ldap.SortKey;
 
@@ -92,7 +91,7 @@
     	// Get all of the actual values
         String contextName = searchDetails.getContextName();
         String contextFilter = searchDetails.getContextFilter();
-        List attrList = searchDetails.getAttributeList();
+        List attrList = searchDetails.getElementList();
         long countLimit = searchDetails.getCountLimit();
     	int searchScope = searchDetails.getSearchScope();
     	SortKey[] sortKeys = searchDetails.getSortKeys();
@@ -105,7 +104,7 @@
     	Iterator iter = attrList.iterator();
     	Iterator eIter = expectedAttrNameList.iterator();
     	while(iter.hasNext()&&eIter.hasNext()) {
-			String actualName = ((Attribute)iter.next()).getID();
+			String actualName = IQueryToLdapSearchParser.getNameFromElement((Column)iter.next());
 			String expectedName = (String)eIter.next();
 			assertEquals(actualName, expectedName);
     	}

Added: trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestLDAPDirectQueryExecution.java
===================================================================
--- trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestLDAPDirectQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestLDAPDirectQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,187 @@
+/*
+ * 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.translator.ldap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.ModificationItem;
+import javax.naming.ldap.LdapContext;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.teiid.cdk.api.TranslationUtility;
+import org.teiid.cdk.unittest.FakeTranslationFactory;
+import org.teiid.language.Command;
+import org.teiid.metadata.RuntimeMetadata;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.TranslatorException;
+
+ at SuppressWarnings("nls")
+public class TestLDAPDirectQueryExecution {
+
+    private static LDAPExecutionFactory TRANSLATOR; 
+
+    @BeforeClass
+    public static void setUp() throws TranslatorException {
+        TRANSLATOR = new LDAPExecutionFactory();
+        TRANSLATOR.start();
+    }	
+    
+    @Test public void testSearch() throws Exception {
+        String input = "exec native('search;context-name=corporate;filter=(objectClass=*);count-limit=5;timout=6;search-scope=ONELEVEL_SCOPE;attributes=uid,cn')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        LdapContext connection = Mockito.mock(LdapContext.class);
+        LdapContext ctx = Mockito.mock(LdapContext.class);
+        Mockito.stub(connection.lookup("corporate")).toReturn(ctx);
+        
+        LDAPDirectSearchQueryExecution execution = (LDAPDirectSearchQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+        execution.execute();
+        LDAPSearchDetails details = execution.getDelegate().getSearchDetails();
+        
+        assertEquals("corporate", details.getContextName());
+        assertEquals("(objectClass=*)", details.getContextFilter());
+        assertEquals(5, details.getCountLimit());
+        assertEquals(1, details.getSearchScope());
+        assertEquals(2, details.getElementList().size());
+        assertEquals("uid", details.getElementList().get(0).getName());
+        assertEquals("cn", details.getElementList().get(1).getName());
+    }    
+    
+    @Test public void testWithoutMarker() throws Exception {
+        String input = "exec native('context-name=corporate;filter=(objectClass=*);count-limit=5;timout=6;search-scope=ONELEVEL_SCOPE;attributes=uid,cn')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        LdapContext connection = Mockito.mock(LdapContext.class);
+        LdapContext ctx = Mockito.mock(LdapContext.class);
+        Mockito.stub(connection.lookup("corporate")).toReturn(ctx);
+        
+        try {
+			LDAPDirectSearchQueryExecution execution = (LDAPDirectSearchQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+			execution.execute();
+			fail("the above should have thrown exception");
+		} catch (ClassCastException e) {
+		}
+    }    
+    
+    @Test public void testDelete() throws Exception {
+        String input = "exec native('delete;uid=doe,ou=people,o=teiid.org')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        LdapContext connection = Mockito.mock(LdapContext.class);
+        LdapContext ctx = Mockito.mock(LdapContext.class);
+        Mockito.stub(connection.lookup("")).toReturn(ctx);
+        
+        LDAPDirectCreateUpdateDeleteQueryExecution execution = (LDAPDirectCreateUpdateDeleteQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+		execution.execute();
+		
+		Mockito.verify(ctx, Mockito.times(1)).destroySubcontext("uid=doe,ou=people,o=teiid.org");
+    }      
+    
+    @Test public void testUpdate() throws Exception {
+        String input = "exec native('update;uid=doe,ou=people,o=teiid.org;attributes=one,two,three', 'one', 2, 3.0)"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        LdapContext connection = Mockito.mock(LdapContext.class);
+        LdapContext ctx = Mockito.mock(LdapContext.class);
+        Mockito.stub(connection.lookup("")).toReturn(ctx);
+        
+        LDAPDirectCreateUpdateDeleteQueryExecution execution = (LDAPDirectCreateUpdateDeleteQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+		execution.execute();
+		
+		ArgumentCaptor<String> nameArgument = ArgumentCaptor.forClass(String.class);
+		ArgumentCaptor<ModificationItem[]> modificationItemArgument = ArgumentCaptor.forClass(ModificationItem[].class);
+		Mockito.verify(ctx).modifyAttributes(nameArgument.capture(),modificationItemArgument.capture());
+
+		assertEquals("uid=doe,ou=people,o=teiid.org", nameArgument.getValue());
+		assertEquals("one", modificationItemArgument.getValue()[0].getAttribute().getID());
+		assertEquals("one", modificationItemArgument.getValue()[0].getAttribute().get());
+		assertEquals("two", modificationItemArgument.getValue()[1].getAttribute().getID());
+		assertEquals(2, modificationItemArgument.getValue()[1].getAttribute().get());
+		assertEquals("three", modificationItemArgument.getValue()[2].getAttribute().getID());
+		assertEquals(new BigDecimal("3.0"), modificationItemArgument.getValue()[2].getAttribute().get());
+    } 
+    
+    @Test public void testCreate() throws Exception {
+        String input = "exec native('create;uid=doe,ou=people,o=teiid.org;attributes=one,two,three', 'one', 2, 3.0)"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        LdapContext connection = Mockito.mock(LdapContext.class);
+        LdapContext ctx = Mockito.mock(LdapContext.class);
+        Mockito.stub(connection.lookup("")).toReturn(ctx);
+        
+        LDAPDirectCreateUpdateDeleteQueryExecution execution = (LDAPDirectCreateUpdateDeleteQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+		execution.execute();
+		
+		ArgumentCaptor<String> nameArgument = ArgumentCaptor.forClass(String.class);
+		ArgumentCaptor<BasicAttributes> createItemArgument = ArgumentCaptor.forClass(BasicAttributes.class);
+		Mockito.verify(ctx).createSubcontext(nameArgument.capture(), createItemArgument.capture());
+
+		assertEquals("uid=doe,ou=people,o=teiid.org", nameArgument.getValue());
+		assertEquals("one", createItemArgument.getValue().get("one").getID());
+		assertEquals("one", createItemArgument.getValue().get("one").get());
+		assertEquals("two", createItemArgument.getValue().get("two").getID());
+		assertEquals(2, createItemArgument.getValue().get("two").get());
+		assertEquals("three", createItemArgument.getValue().get("three").getID());
+		assertEquals(new BigDecimal("3.0"), createItemArgument.getValue().get("three").get());
+    }
+    
+    @Test public void testCreateFail() throws Exception {
+        String input = "exec native('create;uid=doe,ou=people,o=teiid.org;attributes=one,two,three', 'one')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        LdapContext connection = Mockito.mock(LdapContext.class);
+        LdapContext ctx = Mockito.mock(LdapContext.class);
+        Mockito.stub(connection.lookup("")).toReturn(ctx);
+        
+        try {
+			LDAPDirectCreateUpdateDeleteQueryExecution execution = (LDAPDirectCreateUpdateDeleteQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+			execution.execute();
+			fail("should have failed because there are not enough values");
+		} catch (TranslatorException e) {
+		}
+    }    
+}


Property changes on: trunk/connectors/translator-ldap/src/test/java/org/teiid/translator/ldap/TestLDAPDirectQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapExecutionFactory.java
===================================================================
--- trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -23,26 +23,22 @@
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.List;
 
 import javax.sql.DataSource;
 
 import org.olap4j.OlapConnection;
 import org.olap4j.OlapWrapper;
-import org.teiid.language.Call;
+import org.teiid.language.Argument;
+import org.teiid.language.Command;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
-import org.teiid.metadata.MetadataFactory;
-import org.teiid.metadata.Procedure;
-import org.teiid.metadata.ProcedureParameter;
 import org.teiid.metadata.RuntimeMetadata;
-import org.teiid.metadata.BaseColumn.NullType;
-import org.teiid.metadata.ProcedureParameter.Type;
 import org.teiid.translator.ExecutionContext;
 import org.teiid.translator.ExecutionFactory;
-import org.teiid.translator.ProcedureExecution;
+import org.teiid.translator.ResultSetExecution;
 import org.teiid.translator.Translator;
 import org.teiid.translator.TranslatorException;
-import org.teiid.translator.TypeFacility;
 
 @Translator(name="olap", description="A translator for OLAP Cubes")
 public class OlapExecutionFactory extends ExecutionFactory<DataSource, Connection> {
@@ -50,23 +46,13 @@
 	
 	public OlapExecutionFactory() {
 		setSourceRequiredForMetadata(false);
+		setSupportsNativeQueries(true);
+		setNativeQueryProcedureName(INVOKE_MDX);
 	}
 	
-	@Override
-	public void getMetadata(MetadataFactory metadataFactory, Connection conn) throws TranslatorException {
-		Procedure p = metadataFactory.addProcedure(INVOKE_MDX);
-		p.setAnnotation("Invokes a XMLA webservice with provided MDX query that returns an XML result"); //$NON-NLS-1$
-
-		// mdx query in xml form
-		ProcedureParameter param = metadataFactory.addProcedureParameter("request", TypeFacility.RUNTIME_NAMES.STRING, Type.In, p); //$NON-NLS-1$
-		param.setAnnotation("The MDX query to execute"); //$NON-NLS-1$
-		param.setNullType(NullType.Nullable);
-		metadataFactory.addProcedureResultSetColumn("tuple", TypeFacility.RUNTIME_NAMES.OBJECT, p); //$NON-NLS-1$		
-	}
-    
     @Override
-	public ProcedureExecution createProcedureExecution(Call command, ExecutionContext executionContext, RuntimeMetadata metadata, Connection connection) throws TranslatorException {
-    	return new OlapQueryExecution(command, unwrap(connection), executionContext, this);
+   	public ResultSetExecution createDirectExecution(List<Argument> arguments, Command command, ExecutionContext executionContext, RuntimeMetadata metadata, Connection connection) throws TranslatorException {
+    	return new OlapQueryExecution(arguments, command, unwrap(connection), executionContext, this);
 	}    
 
 	private OlapConnection unwrap(Connection conn) throws TranslatorException {

Modified: trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapQueryExecution.java
===================================================================
--- trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapQueryExecution.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-olap/src/main/java/org/teiid/translator/olap/OlapQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -35,7 +35,6 @@
 import org.olap4j.Position;
 import org.olap4j.metadata.Member;
 import org.teiid.language.Argument;
-import org.teiid.language.Call;
 import org.teiid.language.Command;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
@@ -57,8 +56,10 @@
     private CellSetAxis columnsAxis;
     private int colWidth;
     private ListIterator<Position> rowPositionIterator;
+    private String mdxQuery;
     
-	public OlapQueryExecution(Command command, OlapConnection connection, ExecutionContext context, OlapExecutionFactory executionFactory) {
+	public OlapQueryExecution(List<Argument> arguments, Command command, OlapConnection connection, ExecutionContext context, OlapExecutionFactory executionFactory) {
+		this.mdxQuery = (String) arguments.get(0).getArgumentValue().getValue();;
 		this.command = command;
 		this.connection = connection;
 		this.context = context;
@@ -68,11 +69,7 @@
 	@Override
 	public void execute() throws TranslatorException {
 		try {
-			Call procedure = (Call) this.command;
-			List<Argument> arguments = procedure.getArguments();
-			String mdxQuery = (String) arguments.get(0).getArgumentValue().getValue();
 			stmt = this.connection.createStatement();
-			
 			cellSet = stmt.executeOlapQuery(mdxQuery);
 			CellSetAxis rowAxis = this.cellSet.getAxes().get(Axis.ROWS.axisOrdinal());
 			rowPositionIterator = rowAxis.iterator();

Modified: trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForceExecutionFactory.java
===================================================================
--- trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForceExecutionFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForceExecutionFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -29,6 +29,7 @@
 
 import javax.resource.cci.ConnectionFactory;
 
+import org.teiid.language.Argument;
 import org.teiid.language.Call;
 import org.teiid.language.Command;
 import org.teiid.language.QueryExpression;
@@ -49,6 +50,7 @@
 import org.teiid.translator.TypeFacility;
 import org.teiid.translator.UpdateExecution;
 import org.teiid.translator.salesforce.execution.DeleteExecutionImpl;
+import org.teiid.translator.salesforce.execution.DirectQueryExecution;
 import org.teiid.translator.salesforce.execution.InsertExecutionImpl;
 import org.teiid.translator.salesforce.execution.ProcedureExecutionParentImpl;
 import org.teiid.translator.salesforce.execution.QueryExecutionImpl;
@@ -68,6 +70,7 @@
 		setSupportsOrderBy(false);
 		setSupportsOuterJoins(true);
 		setSupportedJoinCriteria(SupportedJoinCriteria.KEY);
+		setSupportsNativeQueries(true);
 	}
 	
 	@TranslatorProperty(display="Audit Model Fields", advanced=true)
@@ -113,7 +116,13 @@
 			throws TranslatorException {
 		return new ProcedureExecutionParentImpl(command, connection, metadata, executionContext);
 	}
+
 	@Override
+	public ResultSetExecution createDirectExecution(List<Argument> arguments, Command command, ExecutionContext executionContext, RuntimeMetadata metadata, SalesforceConnection connection) throws TranslatorException {
+		 return new DirectQueryExecution(arguments, command, connection, metadata, executionContext);
+	}	
+	
+	@Override
 	public void getMetadata(MetadataFactory metadataFactory, SalesforceConnection connection) throws TranslatorException {
 		MetadataProcessor processor = new MetadataProcessor(connection,metadataFactory, this);
 		processor.processMetadata();

Modified: trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForcePlugin.java
===================================================================
--- trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForcePlugin.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/SalesForcePlugin.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -43,6 +43,10 @@
     public static final BundleUtil Util = new BundleUtil(PLUGIN_ID,BUNDLE_NAME,ResourceBundle.getBundle(BUNDLE_NAME));
 
     public static enum Event implements BundleUtil.Event{
-    	TEIID13001
+    	TEIID13001,
+    	TEIID13002,
+    	TEIID13003,
+    	TEIID13004,
+    	TEIID13005,
     }
 }

Added: trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/execution/DirectQueryExecution.java
===================================================================
--- trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/execution/DirectQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/execution/DirectQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,289 @@
+/*
+ * 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.translator.salesforce.execution;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.resource.ResourceException;
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import org.teiid.language.Argument;
+import org.teiid.language.Command;
+import org.teiid.metadata.RuntimeMetadata;
+import org.teiid.translator.DataNotAvailableException;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.ProcedureExecution;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.salesforce.SalesForcePlugin;
+import org.teiid.translator.salesforce.SalesforceConnection;
+import org.w3c.dom.Element;
+
+import com.sforce.soap.partner.QueryResult;
+import com.sforce.soap.partner.sobject.SObject;
+
+public class DirectQueryExecution implements ProcedureExecution  {
+	
+	private static final String DELETE_IDS = "ids"; //$NON-NLS-1$
+	private static final String ATTRIBUTES = "attributes"; //$NON-NLS-1$
+	private static final String TYPE = "type"; //$NON-NLS-1$
+	private static final String ID = "id"; //$NON-NLS-1$
+	
+	private List<Argument> arguments;
+	private Command command;
+	private SalesforceConnection connection; 
+	private RuntimeMetadata metadata;
+	private ExecutionContext context;
+	private QueryResult results;
+	private List<List<Object>> currentBatch;
+	private int updateCount = -1;
+	private boolean updateQuery = false; 
+	
+	public DirectQueryExecution(List<Argument> arguments, Command command, SalesforceConnection connection, RuntimeMetadata metadata, ExecutionContext context) {
+		this.arguments = arguments;
+		this.command = command;
+		this.connection = connection;
+		this.metadata = metadata;
+		this.context = context;
+	}
+
+	@Override
+	public void execute() throws TranslatorException {
+		String query = (String)this.arguments.get(0).getArgumentValue().getValue();
+		if (query.startsWith("search;")) { //$NON-NLS-1$
+			doSelect(query.substring(7));
+		}
+		else if (query.startsWith("create;")) { //$NON-NLS-1$
+			doInsert(query.substring(7));
+		}
+		else if (query.startsWith("update;")) { //$NON-NLS-1$
+			doUpdate(query.substring(7));
+		}
+		else if (query.startsWith("delete;")) { //$NON-NLS-1$
+			doDelete(query.substring(7));
+		}
+		else {
+			throw new TranslatorException(SalesForcePlugin.Util.gs(SalesForcePlugin.Event.TEIID13002));
+		}
+		
+	}
+
+	private void doDelete(String query) throws TranslatorException {
+		List<String> ids = getIds(query);
+		try {
+			this.updateCount = this.connection.delete(ids.toArray(new String[ids.size()]));
+			this.updateQuery = true;
+		} catch (ResourceException e) {
+			throw new TranslatorException(e);
+		}
+	}
+
+	private void doUpdate(String query)  throws TranslatorException {
+		DataPayload payload = buildDataPlayload(query, this.arguments);
+		try {
+			this.updateCount = this.connection.update(Arrays.asList(payload));
+			this.updateQuery = true;
+		} catch (ResourceException e) {
+			throw new TranslatorException(e);
+		}
+	}
+
+	private void doInsert(String query) throws TranslatorException {
+		DataPayload payload = buildDataPlayload(query, this.arguments);
+		try {
+			this.updateCount = this.connection.create(payload);
+			this.updateQuery = true;
+		} catch (ResourceException e) {
+			throw new TranslatorException(e);
+		}
+	}
+
+	private void doSelect(String query) throws TranslatorException {
+		try {
+			this.results = this.connection.query(query, this.context.getBatchSize(), Boolean.FALSE);
+		} catch (ResourceException e) {
+			throw new TranslatorException(e);
+		}
+	}
+
+	@Override
+	public List<?> next() throws TranslatorException, DataNotAvailableException {
+		List<?> vals = getRow(this.results);
+		if (vals == null) {
+			return null;
+		}
+		List<Object[]> row = new ArrayList<Object[]>(1);
+		row.add(vals.toArray(new Object[vals.size()]));
+		return row;		
+	}
+	
+	private List<Object> getRow(QueryResult result) throws TranslatorException {
+
+		// for insert/update/delete clauses
+		if (this.updateQuery) {
+			if (this.updateCount != -1) {
+				List updateResult = Arrays.asList(this.updateCount);
+				this.updateCount = -1;
+				return updateResult;
+			}
+			return null;
+		}
+		
+		// select clauses
+		List<Object> row = null;
+		
+		if(this.currentBatch == null) {
+			this.currentBatch = loadBatch(this.results);
+		}
+		
+		if(!this.currentBatch.isEmpty()) {
+			row = this.currentBatch.remove(0);
+		} 
+		else {
+			if(!result.isDone()) {
+				// fetch more results
+				try {
+					this.results = this.connection.queryMore(results.getQueryLocator(), context.getBatchSize());
+				} catch (ResourceException e) {
+					throw new TranslatorException(e);
+				}
+				this.currentBatch = loadBatch(this.results);
+				
+				// read next row
+				row = this.currentBatch.remove(0);
+			}
+		}
+		return row;
+	}	
+	
+	private List<List<Object>> loadBatch(QueryResult queryResult) {
+		List<List<Object>> batch = new ArrayList<List<Object>>();
+		for(SObject sObject : queryResult.getRecords()) {
+			List<Object> fields = sObject.getAny();
+			List<Object> row = new ArrayList<Object>();
+			if (sObject.getId() != null) {
+				row.add(sObject.getId());
+			}
+			for (Object field:fields) {
+				Element elem = (Element)field;
+				String value = elem.getTextContent();
+				row.add(value);
+			}
+			batch.add(row);
+		}
+		return batch;
+	}
+	
+	@Override
+	public void close() {
+	}
+
+	@Override
+	public void cancel() throws TranslatorException {
+	}
+	
+	private ArrayList<String> getIds(String query) throws TranslatorException {
+		StringTokenizer st = new StringTokenizer(query, ";"); //$NON-NLS-1$
+		if (!st.hasMoreTokens()) {
+			throw new TranslatorException(SalesForcePlugin.Util.gs(SalesForcePlugin.Event.TEIID13003));
+		}
+		
+		ArrayList<String> ids = new ArrayList<String>();
+		
+		while(st.hasMoreElements()) {
+			String var = st.nextToken();
+			int index = var.indexOf('=');
+			if (index == -1) {
+				continue;
+			}
+			String key = var.substring(0, index).trim().toLowerCase();
+			String value = var.substring(index+1).trim();
+			
+			if (key.equalsIgnoreCase(DELETE_IDS)) {
+				StringTokenizer attrTokens = new StringTokenizer(value, ","); //$NON-NLS-1$
+				while (attrTokens.hasMoreElements()) {
+					ids.add(attrTokens.nextToken());
+				}
+			}
+		}
+		return ids;
+	}	
+	
+	private DataPayload buildDataPlayload(String query, List<Argument> arguments) throws TranslatorException {
+		StringTokenizer st = new StringTokenizer(query, ";"); //$NON-NLS-1$
+		if (!st.hasMoreTokens()) {
+			throw new TranslatorException(SalesForcePlugin.Util.gs(SalesForcePlugin.Event.TEIID13004));
+		}
+		
+		ArrayList<JAXBElement> attributes = new ArrayList<JAXBElement>();
+		String type = null;
+		String id = null;
+		
+		while(st.hasMoreElements()) {
+			String var = st.nextToken();
+			
+			int index = var.indexOf('=');
+			if (index == -1) {
+				continue;
+			}
+			String key = var.substring(0, index).trim().toLowerCase();
+			String value = var.substring(index+1).trim();
+			
+			
+			if (key.equalsIgnoreCase(ATTRIBUTES)) {
+				StringTokenizer attrTokens = new StringTokenizer(value, ","); //$NON-NLS-1$
+				int attrCount = 1;
+				while(attrTokens.hasMoreElements()) {
+					String name = attrTokens.nextToken().trim();
+					if (arguments.size() <= attrCount) {
+						throw new TranslatorException(SalesForcePlugin.Util.gs(SalesForcePlugin.Event.TEIID13005, name));
+					}
+					Argument argument = arguments.get(attrCount++);
+					Object  anObj = argument.getArgumentValue().getValue();
+					QName qname = new QName(name);
+				    @SuppressWarnings( "unchecked" )
+				    JAXBElement jbe = new JAXBElement( qname, String.class, anObj );
+					attributes.add(jbe);
+				}
+			}
+			else if (key.equalsIgnoreCase(TYPE)) {
+				type = value;
+			}
+			else if (key.equalsIgnoreCase(ID)) {
+				id = value;
+			}
+		}
+		DataPayload payload = new DataPayload();
+		payload.setID(id);
+		payload.setType(type);
+		payload.setMessageElements(attributes);
+		return payload;
+	}
+
+	@Override
+	public List<?> getOutputParameterValues() throws TranslatorException {
+		return null;
+	}	
+}


Property changes on: trunk/connectors/translator-salesforce/src/main/java/org/teiid/translator/salesforce/execution/DirectQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/connectors/translator-salesforce/src/main/resources/org/teiid/translator/salesforce/i18n.properties
===================================================================
--- trunk/connectors/translator-salesforce/src/main/resources/org/teiid/translator/salesforce/i18n.properties	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/connectors/translator-salesforce/src/main/resources/org/teiid/translator/salesforce/i18n.properties	2012-09-25 22:15:11 UTC (rev 4472)
@@ -37,4 +37,8 @@
 CriteriaVisitor.LIKE.not.supported.on.Id=LIKE criteria are not allowed on columns of native type Id
 CriteriaVisitor.LIKE.not.supported.on.multiselect=LIKE criteria are not allowed on columns of native type Multi-Select Picklist
 
-TEIID13001=Unknown type returned by SalesForce: {0}
\ No newline at end of file
+TEIID13001=Unknown type returned by SalesForce: {0}
+TEIID13002=Unknown request; query must start with one of [search|create|update|delete]
+TEIID13003=The query is missing "id=x,y.." values.
+TEIID13004=The query is missing type, id and attribute values. 
+TEIID13005=The attribute count does not match with the value parameters supplied. 
\ No newline at end of file

Added: trunk/connectors/translator-salesforce/src/test/java/org/teiid/translator/salesforce/execution/TestSalesForceDirectQueryExecution.java
===================================================================
--- trunk/connectors/translator-salesforce/src/test/java/org/teiid/translator/salesforce/execution/TestSalesForceDirectQueryExecution.java	                        (rev 0)
+++ trunk/connectors/translator-salesforce/src/test/java/org/teiid/translator/salesforce/execution/TestSalesForceDirectQueryExecution.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,210 @@
+/*
+ * 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.translator.salesforce.execution;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.teiid.cdk.api.TranslationUtility;
+import org.teiid.cdk.unittest.FakeTranslationFactory;
+import org.teiid.language.Command;
+import org.teiid.metadata.RuntimeMetadata;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.salesforce.SalesForceExecutionFactory;
+import org.teiid.translator.salesforce.SalesforceConnection;
+import org.w3c.dom.Element;
+
+import com.sforce.soap.partner.QueryResult;
+import com.sforce.soap.partner.sobject.SObject;
+
+ at SuppressWarnings("nls")
+public class TestSalesForceDirectQueryExecution {
+
+    private static SalesForceExecutionFactory TRANSLATOR; 
+
+    @BeforeClass
+    public static void setUp() throws TranslatorException {
+        TRANSLATOR = new SalesForceExecutionFactory();
+        TRANSLATOR.start();
+    }	
+    
+    @Test public void testSearch() throws Exception {
+        String input = "exec native('search;SELECT Account.Id, Account.Type, Account.Name FROM Account')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        SalesforceConnection connection = Mockito.mock(SalesforceConnection.class);
+        
+        QueryResult qr = Mockito.mock(QueryResult.class);
+        Mockito.stub(qr.isDone()).toReturn(true);
+        
+        ArrayList<SObject> results = new ArrayList<SObject>();
+        ArrayList<Object> values = new ArrayList<Object>();
+        
+        SObject s = Mockito.mock(SObject.class);
+        //Mockito.stub(s.getId()).toReturn("theID");
+        Mockito.stub(s.getType()).toReturn("Account");
+        results.add(s);
+        
+        Element e1 = Mockito.mock(Element.class);
+        Mockito.stub(e1.getTextContent()).toReturn("The ID");
+        values.add(e1);
+        
+        Element e2 = Mockito.mock(Element.class);
+        Mockito.stub(e2.getTextContent()).toReturn("The Type");
+        values.add(e2);
+        
+        Element e3 = Mockito.mock(Element.class);
+        Mockito.stub(e3.getTextContent()).toReturn("The Name");
+        values.add(e3);        
+        
+        Mockito.stub(s.getAny()).toReturn(values);        
+        Mockito.stub(qr.getRecords()).toReturn(results);
+        Mockito.stub(connection.query("SELECT Account.Id, Account.Type, Account.Name FROM Account", 0, false)).toReturn(qr);
+        
+        DirectQueryExecution execution = (DirectQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+        execution.execute();
+        
+        Mockito.verify(connection, Mockito.times(1)).query("SELECT Account.Id, Account.Type, Account.Name FROM Account", 0, false);
+        
+        assertArrayEquals(new Object[] {"The ID", "The Type", "The Name"}, (Object[])execution.next().get(0));
+        
+    }    
+    
+    @Test public void testWithoutMarker() throws Exception {
+        String input = "exec native('salesforce query')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        SalesforceConnection connection = Mockito.mock(SalesforceConnection.class);
+        
+        try {
+        	DirectQueryExecution execution = (DirectQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+			execution.execute();
+			fail("the above should have thrown exception");
+		} catch (TranslatorException e) {
+		}
+    }    
+    
+    @Test public void testDelete() throws Exception {
+        String input = "exec native('delete;ids=id1,id2')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        SalesforceConnection connection = Mockito.mock(SalesforceConnection.class);
+        
+		ArgumentCaptor<String[]> payloadArgument = ArgumentCaptor.forClass(String[].class);
+		Mockito.stub(connection.delete(payloadArgument.capture())).toReturn(23);
+		
+        DirectQueryExecution execution = (DirectQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+		execution.execute();
+
+		Mockito.verify(connection, Mockito.times(1)).delete(payloadArgument.capture());
+		
+		assertEquals("id1", payloadArgument.getValue()[0]);
+		assertEquals("id2", payloadArgument.getValue()[1]);
+		
+		assertArrayEquals(new Object[] {23}, (Object[])execution.next().get(0));
+    }      
+    
+    @Test public void testUpdate() throws Exception {
+        String input = "exec native('update;id=pk;type=table;attributes=one,two,three', 'one', 2, 3.0)"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        SalesforceConnection connection = Mockito.mock(SalesforceConnection.class);
+        
+        ArgumentCaptor<List> payloadArgument = ArgumentCaptor.forClass(List.class);
+		Mockito.stub(connection.update(payloadArgument.capture())).toReturn(23);
+		
+        DirectQueryExecution execution = (DirectQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+		execution.execute();
+		
+		Mockito.verify(connection).update(payloadArgument.capture());
+		
+		assertEquals(1, payloadArgument.getValue().size());
+		assertEquals("pk", ((DataPayload)payloadArgument.getValue().get(0)).getID());
+		assertEquals("table", ((DataPayload)payloadArgument.getValue().get(0)).getType());
+		assertEquals(3, ((DataPayload)payloadArgument.getValue().get(0)).getMessageElements().size());
+
+		assertArrayEquals(new Object[] {23}, (Object[])execution.next().get(0));
+    } 
+    
+    @Test public void testCreate() throws Exception {
+    	String input = "exec native('create;id=pk;type=table;attributes=one,two,three', 'one', 2, 3.0)"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        SalesforceConnection connection = Mockito.mock(SalesforceConnection.class);
+        
+        ArgumentCaptor<DataPayload> payloadArgument = ArgumentCaptor.forClass(DataPayload.class);
+        Mockito.stub(connection.create(payloadArgument.capture())).toReturn(23);
+        
+        DirectQueryExecution execution = (DirectQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+		execution.execute();
+		
+		
+		Mockito.verify(connection).create(payloadArgument.capture());
+		
+		assertEquals("pk", payloadArgument.getValue().getID());
+		assertEquals("table", payloadArgument.getValue().getType());
+		assertEquals(3, payloadArgument.getValue().getMessageElements().size());
+		
+		assertArrayEquals(new Object[] {23}, (Object[])execution.next().get(0));
+    }
+    
+    @Test public void testCreateFail() throws Exception {
+    	String input = "exec native('create;id=pk;type=table;attributes=one,two,three', 'one')"; 
+
+        TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility();
+        Command command = util.parseCommand(input);
+        ExecutionContext ec = Mockito.mock(ExecutionContext.class);
+        RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class);
+        SalesforceConnection connection = Mockito.mock(SalesforceConnection.class);
+        
+        try {
+        	DirectQueryExecution execution = (DirectQueryExecution)TRANSLATOR.createExecution(command, ec, rm, connection);
+			execution.execute();
+			fail("should have failed because there are not enough values");
+		} catch (TranslatorException e) {
+		}
+    }    
+}


Property changes on: trunk/connectors/translator-salesforce/src/test/java/org/teiid/translator/salesforce/execution/TestSalesForceDirectQueryExecution.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/engine/src/main/java/org/teiid/query/metadata/DirectQueryMetadataRepository.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/metadata/DirectQueryMetadataRepository.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/metadata/DirectQueryMetadataRepository.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -0,0 +1,58 @@
+/*
+ * 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.query.metadata;
+
+import org.teiid.metadata.MetadataFactory;
+import org.teiid.metadata.Procedure;
+import org.teiid.metadata.ProcedureParameter;
+import org.teiid.metadata.BaseColumn.NullType;
+import org.teiid.metadata.ProcedureParameter.Type;
+import org.teiid.translator.ExecutionFactory;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.TypeFacility;
+
+/**
+ * This Metadata repository adds the "native" procedure to all the execution factories that support them. 
+ */
+public class DirectQueryMetadataRepository extends BaseMetadataRepository {
+	
+	@Override
+	public void loadMetadata(MetadataFactory factory, ExecutionFactory executionFactory, Object connectionFactory) throws TranslatorException {
+
+		if (executionFactory != null && executionFactory.supportsNativeQueries()) {
+			Procedure p = factory.addProcedure(executionFactory.getNativeQueryProcedureName());
+			p.setAnnotation("Invokes translator with provided native query that returns result in array of values"); //$NON-NLS-1$
+
+			ProcedureParameter param = factory.addProcedureParameter("request", TypeFacility.RUNTIME_NAMES.STRING, Type.In, p); //$NON-NLS-1$
+			param.setAnnotation("The native query to execute"); //$NON-NLS-1$
+			param.setNullType(NullType.No_Nulls);
+
+			param = factory.addProcedureParameter("variable", TypeFacility.RUNTIME_NAMES.OBJECT, Type.In, p); //$NON-NLS-1$
+			param.setAnnotation("Any number of varaibles, depends upon how a translator uses them individually"); //$NON-NLS-1$
+			param.setNullType(NullType.Nullable);
+			param.setVarArg(true);
+			
+			factory.addProcedureResultSetColumn("tuple", TypeFacility.RUNTIME_NAMES.OBJECT, p); //$NON-NLS-1$		
+		}
+		super.loadMetadata(factory, executionFactory, connectionFactory);
+	}	
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/metadata/DirectQueryMetadataRepository.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -114,6 +114,14 @@
         Table lobTable = createPhysicalGroup("LobTbl", lob); //$NON-NLS-1$
         Table library = createPhysicalGroup("LOB_TESTING_ONE", lob); //$NON-NLS-1$
         
+        // add direct query procedure
+        ColumnSet<Procedure> nativeProcResults = createResultSet("bqt1.nativers", new String[] {"tuple"}, new String[] { DataTypeManager.DefaultDataTypes.OBJECT}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        ProcedureParameter nativeparam = createParameter("param", ParameterInfo.IN, DataTypeManager.DefaultDataTypes.STRING); //$NON-NLS-1$
+        ProcedureParameter vardic = createParameter("varag", ParameterInfo.IN, DataTypeManager.DefaultDataTypes.OBJECT); //$NON-NLS-1$
+        vardic.setVarArg(true);
+        Procedure nativeProc = createStoredProcedure("native", bqt1, Arrays.asList(nativeparam,vardic));  //$NON-NLS-1$ //$NON-NLS-2$
+        nativeProc.setResultSet(nativeProcResults);        
+        
         createElements( library, new String[] { "CLOB_COLUMN", "BLOB_COLUMN", "KEY_EMULATOR" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
         		new String[] { DataTypeManager.DefaultDataTypes.CLOB, DataTypeManager.DefaultDataTypes.BLOB, DataTypeManager.DefaultDataTypes.INTEGER }); 
 
@@ -1014,6 +1022,13 @@
         
         //end case 3281
         
+        ColumnSet<Procedure> nativeProcResults = createResultSet("pm1.nativers", new String[] {"tuple"}, new String[] { DataTypeManager.DefaultDataTypes.OBJECT}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        ProcedureParameter nativeparam = createParameter("param", ParameterInfo.IN, DataTypeManager.DefaultDataTypes.STRING); //$NON-NLS-1$
+        ProcedureParameter vardic = createParameter("varag", ParameterInfo.IN, DataTypeManager.DefaultDataTypes.OBJECT); //$NON-NLS-1$
+        vardic.setVarArg(true);
+        Procedure nativeProc = createStoredProcedure("native", pm1, Arrays.asList(nativeparam,vardic));  //$NON-NLS-1$ //$NON-NLS-2$
+        nativeProc.setResultSet(nativeProcResults);
+        
         ColumnSet<Procedure> rs3 = createResultSet("pm1.rs3", new String[] { "e1", "e2" }, new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
         Procedure sp1 = createStoredProcedure("sp1", pm1, null);  //$NON-NLS-1$ //$NON-NLS-2$
         sp1.setResultSet(rs3);

Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/pom.xml	2012-09-25 22:15:11 UTC (rev 4472)
@@ -252,7 +252,7 @@
 		<dependency>
 			<groupId>org.mockito</groupId>
 			<artifactId>mockito-all</artifactId>
-			<version>1.5</version>
+			<version>1.9.0</version>
 			<scope>test</scope>
 		</dependency>
 	</dependencies>

Modified: trunk/runtime/src/main/java/org/teiid/runtime/AbstractVDBDeployer.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/runtime/AbstractVDBDeployer.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/runtime/src/main/java/org/teiid/runtime/AbstractVDBDeployer.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -45,6 +45,7 @@
 import org.teiid.metadata.MetadataStore;
 import org.teiid.query.metadata.DDLMetadataRepository;
 import org.teiid.query.metadata.NativeMetadataRepository;
+import org.teiid.query.metadata.DirectQueryMetadataRepository;
 import org.teiid.translator.TranslatorException;
 
 public abstract class AbstractVDBDeployer {
@@ -76,11 +77,14 @@
 	private MetadataRepository<?, ?> getMetadataRepository(VDBMetaData vdb, ModelMetaData model, MetadataRepository<?, ?> defaultRepo) throws VirtualDatabaseException {
 		if (model.getSchemaSourceType() == null) {
 			if (!vdb.isDynamic()) {
+				defaultRepo.setNext(new DirectQueryMetadataRepository());
 				return defaultRepo;
 			}
 			
 			if (model.isSource()) {
-				return new NativeMetadataRepository();
+				NativeMetadataRepository repo =  new NativeMetadataRepository();
+				repo.setNext(new DirectQueryMetadataRepository());
+				return repo;
 			}
 			throw new VirtualDatabaseException(RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40094, model.getName(), vdb.getName(), vdb.getVersion(), null));
 		}
@@ -88,7 +92,8 @@
 		MetadataRepository<?, ?> first = null;
 		MetadataRepository<?, ?> current = null;
 		MetadataRepository<?, ?> previous = null;
-		StringTokenizer st = new StringTokenizer(model.getSchemaSourceType(), ","); //$NON-NLS-1$
+		String schemaTypes = model.getSchemaSourceType();
+		StringTokenizer st = new StringTokenizer(schemaTypes, ","); //$NON-NLS-1$
 		while (st.hasMoreTokens()) {
 			String repoType = st.nextToken().trim();
 			current = getMetadataRepository(repoType);
@@ -106,6 +111,12 @@
 			previous = current;
 			current = null;
 		}
+		
+		// TODO:there is good chance that the instances of metadata factory sharing is not good between models,
+		// may that be for chaining purposes, we should do metadata repository factory model here. 
+		if (model.getModelType() == ModelMetaData.Type.PHYSICAL) {
+			previous.setNext(new DirectQueryMetadataRepository());
+		}
 		return first;
 	}
 	

Modified: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestExecutionReuse.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestExecutionReuse.java	2012-09-25 18:58:05 UTC (rev 4471)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestExecutionReuse.java	2012-09-25 22:15:11 UTC (rev 4472)
@@ -21,7 +21,8 @@
  */
 package org.teiid.dqp.internal.process;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -35,9 +36,9 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mockito;
-import org.mockito.internal.progress.OngoingStubbing;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.mockito.stubbing.DeprecatedOngoingStubbing;
 import org.teiid.client.util.ResultsFuture;
 import org.teiid.core.util.UnitTestUtil;
 import org.teiid.dqp.internal.datamgr.ConnectorManager;
@@ -100,9 +101,9 @@
 	@Before public void setup() throws DataNotAvailableException, TranslatorException {
 		execution = Mockito.mock(FakeReusableExecution.class);
 		ec = null;
-		OngoingStubbing stubbing = Mockito.stub(execution.next()).toReturn((List) Arrays.asList((Object)null)).toReturn(null);
+		DeprecatedOngoingStubbing stubbing = Mockito.stub(execution.next()).toReturn((List) Arrays.asList((Object)null)).toReturn(null);
 		for (int i = 1; i < EXEC_COUNT; i++) {
-			stubbing.toReturn((List<Object>) Arrays.asList((Object)null)).toReturn(null);
+			stubbing.toReturn(Arrays.asList((Object)null)).toReturn(null);
 		}
 		Mockito.doAnswer(new Answer<Void>() {
 			@Override



More information about the teiid-commits mailing list