Author: rareddy
Date: 2010-10-12 16:23:14 -0400 (Tue, 12 Oct 2010)
New Revision: 2644
Modified:
trunk/documentation/reference/src/main/docbook/en-US/content/translators.xml
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceElementReplacementVisitor.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceMetadataWrapper.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalPlan.java
trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/dqp/internal/process/multisource/TestMultiSourceElementReplacementVisitor.java
trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-1273, TEIID-1295, TEIID-1296: multi-source insert capability is added. Also
corrected update count and mark them as transactional when more than single source is
involved.
Modified: trunk/documentation/reference/src/main/docbook/en-US/content/translators.xml
===================================================================
---
trunk/documentation/reference/src/main/docbook/en-US/content/translators.xml 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/documentation/reference/src/main/docbook/en-US/content/translators.xml 2010-10-12
20:23:14 UTC (rev 2644)
@@ -1229,7 +1229,7 @@
<para>
To mark a model as multi-source, the user needs to supply property called
<property>supports-multi-source-bindings</property>, in the
"vdb.xml" file.
- Also, the user needs to define multiple sources. Here is code example showing
single model with
+ Also, the user needs to define multiple sources. Here is code example showing
dynamic vdb with single model with
multiple sources defined.
</para>
@@ -1258,12 +1258,13 @@
<programlisting language="SQL"><![CDATA[select * from table
where SOURCE_NAME = 'newyork'
update table column=value where SOURCE_NAME='chicago'
-delete from table where column = x and
SOURCE_NAME='la']]></programlisting>
+delete from table where column = x and SOURCE_NAME='la'
+insert into table (column, SOURCE_NAME) VALUES ('value',
'newyork')]]></programlisting>
<para>
- Note that when user do not supply the "SOURCE_NAME" in the criteria, it
applies
- to all the sources. Unfortunately Teiid currently does not support INSERT, this
- planned for future releases. Another useful feature along with this feature is
+ Note that when user do not supply the "SOURCE_NAME" in the criteria,
the command applies
+ to all the sources. If SOURCE_NAME supplied, the query is executed only aginst
the source specified.
+ Another useful feature along with this feature is
"partial results" to skip unavailable sources if they are down.
</para>
@@ -1273,7 +1274,7 @@
limited, so if you need to use this feature build the VDB as usual in
the Teiid Designer and then edit the "vdb.xml" file in the VDB
archive
using a Text editor to add the additional sources as defined above.
- You must deploy a data source for each source defined.
+ You must deploy a separate data source for each source defined in the xml
file.
</para>
</note>
Modified:
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceElementReplacementVisitor.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceElementReplacementVisitor.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceElementReplacementVisitor.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -23,6 +23,11 @@
package org.teiid.dqp.internal.process.multisource;
import org.teiid.core.types.DataTypeManager;
+import org.teiid.query.rewriter.QueryRewriter;
+import org.teiid.query.sql.lang.From;
+import org.teiid.query.sql.lang.Insert;
+import org.teiid.query.sql.lang.Query;
+import org.teiid.query.sql.lang.Select;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
@@ -50,4 +55,29 @@
return expr;
}
+
+ public void visit(Insert obj) {
+ for (int i = 0; i < obj.getVariables().size(); i++) {
+ Expression expr = (Expression)obj.getVariables().get(i);
+ if(expr instanceof ElementSymbol) {
+ ElementSymbol elem = (ElementSymbol) expr;
+ Object metadataID = elem.getMetadataID();
+ if(metadataID instanceof MultiSourceElement) {
+ Constant source = (Constant)obj.getValues().get(i);
+ obj.getVariables().remove(i);
+ obj.getValues().remove(i);
+ if (!source.getValue().equals(this.bindingName)) {
+ Select select = new Select(obj.getVariables());
+ From from = new From();
+ from.addGroup(obj.getGroup());
+ Query query = new Query();
+ query.setSelect(select);
+ query.setFrom(from);
+ query.setCriteria(QueryRewriter.FALSE_CRITERIA);
+ obj.setQueryExpression(query);
+ }
+ }
+ }
+ }
+ }
}
Modified:
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceMetadataWrapper.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceMetadataWrapper.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourceMetadataWrapper.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -271,7 +271,7 @@
case SupportConstants.Element.SELECT:
return true;
case SupportConstants.Element.UPDATE:
- return false;
+ return true;
case SupportConstants.Element.DEFAULT_VALUE:
return false;
case SupportConstants.Element.AUTO_INCREMENT:
Modified:
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -33,20 +33,31 @@
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.id.IDGenerator;
+import org.teiid.core.types.DataTypeManager;
import org.teiid.dqp.internal.process.DQPWorkContext;
+import org.teiid.language.SQLConstants.NonReserved;
import org.teiid.query.analysis.AnalysisRecord;
+import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.relational.PlanToProcessConverter;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
import org.teiid.query.processor.relational.AccessNode;
+import org.teiid.query.processor.relational.GroupingNode;
import org.teiid.query.processor.relational.NullNode;
+import org.teiid.query.processor.relational.ProjectNode;
import org.teiid.query.processor.relational.RelationalNode;
import org.teiid.query.processor.relational.RelationalNodeUtil;
import org.teiid.query.processor.relational.UnionAllNode;
+import org.teiid.query.resolver.util.ResolverVisitor;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.navigator.DeepPreOrderNavigator;
+import org.teiid.query.sql.symbol.AggregateSymbol;
+import org.teiid.query.sql.symbol.Constant;
+import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.ExpressionSymbol;
+import org.teiid.query.sql.symbol.Function;
import org.teiid.query.util.CommandContext;
@@ -102,6 +113,10 @@
// Replace all multi-source elements with the source name
DeepPreOrderNavigator.doVisit(command, new
MultiSourceElementReplacementVisitor(sourceName));
+ if (!RelationalNodeUtil.shouldExecute(command, false)) {
+ continue;
+ }
+
// Rewrite the command now that criteria may have been simplified
try {
command = QueryRewriter.rewrite(command, metadata, null);
@@ -133,17 +148,44 @@
}
default:
{
- // More than 1 access node - replace with a union
+
+ UnionAllNode unionNode = new UnionAllNode(getID());
+ unionNode.setElements(accessNode.getElements());
- UnionAllNode unionNode = new UnionAllNode(getID());
- unionNode.setElements(accessNode.getElements());
-
- RelationalNode parent = unionNode;
-
for (AccessNode newNode : accessNodes) {
- unionNode.addChild(newNode);
+ unionNode.addChild(newNode);
}
+
+ RelationalNode parent = unionNode;
+
+ // More than 1 access node - replace with a union
+ if (RelationalNodeUtil.isUpdate(accessNode.getCommand())) {
+
+ GroupingNode groupNode = new GroupingNode(getID());
+ AggregateSymbol sumCount = new AggregateSymbol("SumCount",
NonReserved.SUM, false, (Expression)accessNode.getElements().get(0)); //$NON-NLS-1$
+ List outputElements = new ArrayList();
+ outputElements.add(sumCount);
+ groupNode.setElements(outputElements);
+ groupNode.addChild(unionNode);
+
+ ProjectNode projectNode = new ProjectNode(getID());
+ // two converts because, the 2nd one does not resolve because of no
metadata about the expression.
+ Function convertFunc = new Function(FunctionLibrary.CONVERT, new
Expression[] {new Constant(new Long(0)), new
Constant(DataTypeManager.DefaultDataTypes.INTEGER)});
+ ResolverVisitor.resolveLanguageObject(convertFunc, metadata);
+ Function convertFunc2 = new Function(FunctionLibrary.CONVERT, new
Expression[] {sumCount, new Constant(DataTypeManager.DefaultDataTypes.INTEGER)});
+ convertFunc2.setFunctionDescriptor(convertFunc.getFunctionDescriptor());
+
+ Expression rowCount = new ExpressionSymbol("RowCount",
convertFunc2); //$NON-NLS-1$
+ outputElements = new ArrayList();
+ outputElements.add(rowCount);
+ projectNode.setElements(outputElements);
+ projectNode.setSelectSymbols(outputElements);
+ projectNode.addChild(groupNode);
+
+ parent = projectNode;
+ }
+ parent.setMultiSource(true);
return parent;
}
}
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -87,6 +87,8 @@
/** Child nodes, usually just 1 or 2 */
private RelationalNode[] children = new RelationalNode[2];
+
+ private boolean multiSource;
protected RelationalNode() {
@@ -596,4 +598,12 @@
}
return processingState;
}
+
+ public boolean isMultiSource() {
+ return multiSource;
+ }
+
+ public void setMultiSource(boolean multiSource) {
+ this.multiSource = multiSource;
+ }
}
\ No newline at end of file
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -29,6 +29,7 @@
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Delete;
+import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.Limit;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.QueryCommand;
@@ -123,6 +124,13 @@
return true;
}
break;
+ case Command.TYPE_INSERT:
+ Insert insert = (Insert) command;
+ QueryCommand expr = insert.getQueryExpression();
+ if (expr != null) {
+ return shouldExecute(expr, simplifyCriteria);
+ }
+ return true;
case Command.TYPE_UPDATE:
Update update = (Update) command;
@@ -174,7 +182,7 @@
* @return
* @since 4.2
*/
- static boolean isUpdate(Command command) {
+ public static boolean isUpdate(Command command) {
int commandType = command.getType();
return commandType == Command.TYPE_INSERT ||
commandType == Command.TYPE_UPDATE ||
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalPlan.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalPlan.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalPlan.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -239,6 +239,9 @@
}
}
}
+ if (this.root.isMultiSource()) {
+ return true;
+ }
return requiresTransaction(transactionalReads, root);
}
Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-10-12
18:04:46 UTC (rev 2643)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -42,6 +42,7 @@
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.EquivalenceUtil;
+import org.teiid.dqp.internal.process.multisource.MultiSourceElement;
import org.teiid.query.QueryPlugin;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.function.FunctionLibrary;
@@ -788,7 +789,8 @@
ElementSymbol nextElmnt = (ElementSymbol) ignoreIter.next();
if(!getMetadata().elementSupports(nextElmnt.getMetadataID(),
SupportConstants.Element.DEFAULT_VALUE) &&
!getMetadata().elementSupports(nextElmnt.getMetadataID(),
SupportConstants.Element.NULL) &&
- !getMetadata().elementSupports(nextElmnt.getMetadataID(),
SupportConstants.Element.AUTO_INCREMENT)) {
+ !getMetadata().elementSupports(nextElmnt.getMetadataID(),
SupportConstants.Element.AUTO_INCREMENT) &&
+ !(nextElmnt.getMetadataID() instanceof MultiSourceElement)) {
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0053", new
Object[] {insertGroup, nextElmnt}), nextElmnt); //$NON-NLS-1$
}
}
@@ -843,6 +845,11 @@
if(! getMetadata().elementSupports(elementID.getMetadataID(),
SupportConstants.Element.UPDATE)) {
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0059", elementID),
elementID); //$NON-NLS-1$
}
+
+ Object metadataID = elementID.getMetadataID();
+ if (metadataID instanceof MultiSourceElement){
+
handleValidationError(QueryPlugin.Util.getString("multi_source_update_not_allowed",
elementID), elementID); //$NON-NLS-1$
+ }
// Check that right expression is a constant and is non-null
Expression value = entry.getValue();
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-10-12 18:04:46
UTC (rev 2643)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-10-12 20:23:14
UTC (rev 2644)
@@ -860,4 +860,5 @@
RequestWorkItem.cache_nondeterministic=Caching command '{0}'' at a session
level, but less deterministic functions were evaluated.
not_found_cache=Results not found in cache
failed_to_unwrap_connection=Failed to unwrap the source connection.
-connection_factory_not_found=Failed to the Connection Factory with JNDI name {0}. Please
check the name for spelling or deploy the Connection Factory with specified name.
\ No newline at end of file
+connection_factory_not_found=Failed to the Connection Factory with JNDI name {0}. Please
check the name for spelling or deploy the Connection Factory with specified name.
+multi_source_update_not_allowed=Update of the column {0} is not allowed.
\ No newline at end of file
Modified:
trunk/engine/src/test/java/org/teiid/dqp/internal/process/multisource/TestMultiSourceElementReplacementVisitor.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/dqp/internal/process/multisource/TestMultiSourceElementReplacementVisitor.java 2010-10-12
18:04:46 UTC (rev 2643)
+++
trunk/engine/src/test/java/org/teiid/dqp/internal/process/multisource/TestMultiSourceElementReplacementVisitor.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -45,7 +45,7 @@
QueryMetadataInterface metadata = FakeMetadataFactory.exampleMultiBinding();
Set<String> multiSourceModels = new HashSet<String>();
- multiSourceModels.add("MultiModel");
+ multiSourceModels.add("MultiModel"); //$NON-NLS-1$
MultiSourceMetadataWrapper wrapper = new MultiSourceMetadataWrapper(metadata,
multiSourceModels);
return wrapper;
@@ -121,5 +121,23 @@
getMetadata(),
"SELECT a FROM MultiModel.Phys WHERE 'x' = (SELECT b FROM
MultiModel.Phys WHERE 'x' IN ('x'))"); //$NON-NLS-1$
}
+
+ public void testInsertMatching() throws Exception {
+ helpTest("INSERT INTO MultiModel.Phys(a, SOURCE_NAME) VALUES('a',
'x')", //$NON-NLS-1$
+ getMetadata(),
+ "INSERT INTO MultiModel.Phys (a, SOURCE_NAME) SELECT a WHERE
'1' = '2'"); //$NON-NLS-1$
+ }
+
+ public void testInsertNotMatching() throws Exception {
+ helpTest("INSERT INTO MultiModel.Phys(a, SOURCE_NAME) VALUES('a',
'y')", //$NON-NLS-1$
+ getMetadata(),
+ "INSERT INTO MultiModel.Phys (a, SOURCE_NAME) SELECT a WHERE
'1' = '2'"); //$NON-NLS-1$
+ }
+
+ public void testInsertAll() throws Exception {
+ helpTest("INSERT INTO MultiModel.Phys(a) VALUES('a')",
//$NON-NLS-1$
+ getMetadata(),
+ "INSERT INTO MultiModel.Phys (a) VALUES ('a')");
//$NON-NLS-1$
+ }
}
Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2010-10-12
18:04:46 UTC (rev 2643)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2010-10-12
20:23:14 UTC (rev 2644)
@@ -22,7 +22,9 @@
package org.teiid.query.validator;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
@@ -44,6 +46,7 @@
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.DataTypeManager;
+import org.teiid.dqp.internal.process.multisource.MultiSourceMetadataWrapper;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.mapping.xml.MappingDocument;
@@ -2030,4 +2033,10 @@
helpValidate("SELECT e2, (SELECT e1, e2 FROM pm1.g1 WHERE e2 = '3')
FROM pm1.g2", new String[] {"SELECT e1, e2 FROM pm1.g1 WHERE e2 =
'3'"}, FakeMetadataFactory.example1Cached()); //$NON-NLS-1$ //$NON-NLS-2$
}
+ @Test public void testDisallowUpdateOnMultisourceElement() throws Exception {
+ Set<String> models = new HashSet<String>();
+ models.add("pm1");
+ ValidatorReport report = helpValidateInModeler("pm1.vsp36",
"UPDATE PM1.G1 set SOURCE_NAME='blah'", new
MultiSourceMetadataWrapper(FakeMetadataFactory.example1Cached(), models)); //$NON-NLS-1$
+ assertEquals(report.toString(), 1, report.getItems().size());
+ }
}