diff --git a/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/CassandraExecutionFactory.java b/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/CassandraExecutionFactory.java index 4aebe1bb24..8aceb94554 100644 --- a/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/CassandraExecutionFactory.java +++ b/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/CassandraExecutionFactory.java @@ -22,22 +22,29 @@ package org.teiid.translator.cassandra; +import java.util.List; + import javax.resource.cci.ConnectionFactory; import org.teiid.core.BundleUtil; +import org.teiid.language.Argument; +import org.teiid.language.Call; import org.teiid.language.Command; import org.teiid.language.QueryExpression; import org.teiid.language.Select; +import org.teiid.language.visitor.SQLStringVisitor; import org.teiid.logging.LogConstants; import org.teiid.logging.LogManager; import org.teiid.metadata.MetadataFactory; import org.teiid.metadata.RuntimeMetadata; 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.UpdateExecution; +import org.teiid.translator.cassandra.execution.CassandraDirectQueryExecution; import org.teiid.translator.cassandra.execution.CassandraQueryExecution; import org.teiid.translator.cassandra.execution.CassandraUpdateExecution; import org.teiid.translator.cassandra.metadata.CassandraMetadataProcessor; @@ -65,7 +72,26 @@ public UpdateExecution createUpdateExecution(Command command, ExecutionContext executionContext, RuntimeMetadata metadata, CassandraConnection connection) throws TranslatorException { return new CassandraUpdateExecution(command, executionContext, metadata, connection); - } + } + + @Override + public ProcedureExecution createProcedureExecution(Call command, + ExecutionContext executionContext, RuntimeMetadata metadata, + CassandraConnection connection) throws TranslatorException { + String nativeQuery = command.getMetadataObject().getProperty(SQLStringVisitor.TEIID_NATIVE_QUERY, false); + if (nativeQuery != null) { + return new CassandraDirectQueryExecution(nativeQuery, command.getArguments(), command, connection, executionContext); + } + throw new TranslatorException("Missing native-query extension metadata."); //$NON-NLS-1$ + } + + @Override + public ProcedureExecution createDirectExecution(List arguments, + Command command, ExecutionContext executionContext, + RuntimeMetadata metadata, CassandraConnection connection) + throws TranslatorException { + return new CassandraDirectQueryExecution((String) arguments.get(0).getArgumentValue().getValue(), arguments.subList(1, arguments.size()), command, connection, executionContext); + } @Override public void getMetadata(MetadataFactory metadataFactory, diff --git a/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraDirectQueryExecution.java b/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraDirectQueryExecution.java new file mode 100644 index 0000000000..58491cd080 --- /dev/null +++ b/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraDirectQueryExecution.java @@ -0,0 +1,67 @@ +/* + * 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.cassandra.execution; + +import java.util.List; + +import org.teiid.language.Argument; +import org.teiid.language.Command; +import org.teiid.language.Literal; +import org.teiid.language.visitor.SQLStringVisitor; +import org.teiid.translator.ExecutionContext; +import org.teiid.translator.ProcedureExecution; +import org.teiid.translator.TranslatorException; +import org.teiid.translator.cassandra.CassandraConnection; + +public class CassandraDirectQueryExecution extends CassandraQueryExecution implements ProcedureExecution { + + private String cql; + private List arguments; + + public CassandraDirectQueryExecution(String cql, List arguments, Command command, CassandraConnection connection, ExecutionContext context){ + super(command, connection, context); + this.arguments = arguments; + this.cql = cql; + } + + @Override + public void execute() throws TranslatorException { + StringBuilder buffer = new StringBuilder(); + SQLStringVisitor.parseNativeQueryParts(cql, arguments, buffer, new SQLStringVisitor.Substitutor() { + + @Override + public void substitute(Argument arg, StringBuilder builder, int index) { + Literal argumentValue = arg.getArgumentValue(); + builder.append(argumentValue); + } + }); + String source_cql = buffer.toString(); + execute(source_cql); + } + + @Override + public List getOutputParameterValues() throws TranslatorException { + return null; + } + +} diff --git a/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraQueryExecution.java b/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraQueryExecution.java index 4d7016b409..3462b66631 100644 --- a/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraQueryExecution.java +++ b/connectors/translator-cassandra/src/main/java/org/teiid/translator/cassandra/execution/CassandraQueryExecution.java @@ -26,7 +26,7 @@ import java.util.ArrayList; import java.util.List; -import org.teiid.language.Select; +import org.teiid.language.Command; import org.teiid.logging.LogConstants; import org.teiid.logging.LogManager; import org.teiid.translator.DataNotAvailableException; @@ -41,12 +41,12 @@ public class CassandraQueryExecution implements ResultSetExecution { - private Select query; + private Command query; private CassandraConnection connection; private ResultSet resultSet = null; private ExecutionContext executionContext; - public CassandraQueryExecution(Select query, CassandraConnection connection, ExecutionContext context){ + public CassandraQueryExecution(Command query, CassandraConnection connection, ExecutionContext context){ this.query = query; this.connection = connection; this.executionContext = context; @@ -69,6 +69,10 @@ public void execute() throws TranslatorException { CassandraSQLVisitor visitor = new CassandraSQLVisitor(); visitor.translateSQL(query); String cql = visitor.getTranslatedSQL(); + execute(cql); + } + + protected void execute(String cql) throws TranslatorException { LogManager.logDetail(LogConstants.CTX_CONNECTOR, "Source-Query:", cql); //$NON-NLS-1$ try { resultSet = connection.executeQuery(cql); diff --git a/connectors/translator-cassandra/src/test/java/org/teiid/translator/cassandra/TestNativeCassandra.java b/connectors/translator-cassandra/src/test/java/org/teiid/translator/cassandra/TestNativeCassandra.java new file mode 100644 index 0000000000..1b317d21fc --- /dev/null +++ b/connectors/translator-cassandra/src/test/java/org/teiid/translator/cassandra/TestNativeCassandra.java @@ -0,0 +1,77 @@ +/* + * 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.cassandra; + +import org.junit.Test; +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.query.metadata.TransformationMetadata; +import org.teiid.query.unittest.RealMetadataFactory; +import org.teiid.translator.Execution; +import org.teiid.translator.ExecutionContext; +import org.teiid.translator.TranslatorException; + +@SuppressWarnings("nls") +public class TestNativeCassandra { + + @Test public void testDirect() throws TranslatorException { + CassandraExecutionFactory cef = new CassandraExecutionFactory(); + cef.setSupportsNativeQueries(true); + + String input = "call native('select $1', 'a')"; + + TranslationUtility util = FakeTranslationFactory.getInstance().getExampleTranslationUtility(); + Command command = util.parseCommand(input); + ExecutionContext ec = Mockito.mock(ExecutionContext.class); + RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class); + CassandraConnection connection = Mockito.mock(CassandraConnection.class); + + Execution execution = cef.createExecution(command, ec, rm, connection); + execution.execute(); + + Mockito.verify(connection).executeQuery("select 'a'"); + } + + @Test public void testNativeQuery() throws Exception { + CassandraExecutionFactory cef = new CassandraExecutionFactory(); + cef.setSupportsNativeQueries(true); + + String input = "call proc('a', 1)"; + + TransformationMetadata metadata = RealMetadataFactory.fromDDL("create foreign procedure proc (in x string, in y integer) options (\"teiid_rel:native-query\" 'delete from $1 where $2')", "x", "y"); + TranslationUtility util = new TranslationUtility(metadata); + Command command = util.parseCommand(input); + ExecutionContext ec = Mockito.mock(ExecutionContext.class); + RuntimeMetadata rm = Mockito.mock(RuntimeMetadata.class); + CassandraConnection connection = Mockito.mock(CassandraConnection.class); + + Execution execution = cef.createExecution(command, ec, rm, connection); + execution.execute(); + + Mockito.verify(connection).executeQuery("delete from 'a' where 1"); + } + +}