Author: shawkins
Date: 2010-12-20 11:52:45 -0500 (Mon, 20 Dec 2010)
New Revision: 2787
Modified:
trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml
trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.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/query/processor/TestInherintlyUpdatableViews.java
trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
Log:
TEIID-1376 adding support for partition wise joins. also updating the docs and allowing
for inserts against views defined by partitioned unions
Modified:
trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml
===================================================================
---
trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml 2010-12-20
16:52:45 UTC (rev 2787)
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
-[
- <!ENTITY access_pattern "<link linkend='access_patterns'>access
patterns</link>">
-]>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="federated_planning">
<title>Federated Planning</title>
<para>Teiid at its core is a federated relational query
@@ -173,7 +170,7 @@
data retrieved from the second source and the number of join
comparisons that must be performed.</para>
<para> The conditions when a dependent join is used are determined
- by the query planner based on &access_pattern;, hints, and
+ by the query planner based on <xref linkend='access_patterns'/>,
hints, and
costing information.</para>
<para>
Teiid supports the MAKEDEP and MAKENOTDEP hints. Theses are
@@ -181,7 +178,7 @@
<link linkend="option_clause">OPTION clause</link>
or directly in the
<link linkend="from_clause">FROM clause</link>
- . As long as all &access_patterns; can be met, the MAKEDEP and
+ . As long as all <xref linkend='access_patterns'/> can be met, the
MAKEDEP and
MAKENOTDEP hints override any use of costing information.
</para>
<tip>
@@ -248,6 +245,18 @@
treated as an optional join and does not require a hint.</para>
</tip>
</section>
+ <section id="partitioned_union">
+ <title>Partitioned Union</title>
+ <para>Union partitioning is inferred from the transformation/inline view. If
one (or more) of the UNION columns is defined by constants and/or has WHERE clause IN
predicates containing only constants
+ that make each branch mutually exclusive, then the UNION is considered partitioned.
+ UNION ALL must be used and the UNION cannot have a LIMIT, WITH, or ORDER BY clause
(although individual branches may use LIMIT, WITH, or ORDER BY).
+ Partitioning values should not be null.
+ For example the view definition "select 1 as x, y from foo union all select z,
a from foo1 where z in (2, 3)" would be considered partitioned on column x,
+ since the first branch can only be the value 1 and the second branch can only be
the values 2 or 3.
+ Note that more advanced or explicit partition could be considered in the future.
+ The concept of a partitioned union is used for performing partition-wise joins and
in <xref linkend="updatable_views"/>.
+ </para>
+ </section>
<section id="standard_relational_techniques">
<title>Standard Relational Techniques</title>
<para>
@@ -697,7 +706,7 @@
gets pushed to the source. Later rules focus on either pushing stuff
under the access or pulling the access node up the tree to move more
work down to the data sources. This rule is also responsible for
- placing &access_patterns;.</para>
+ placing <xref linkend='access_patterns'/>.</para>
</listitem>
<listitem>
<para>RulePushSelectCriteria - pushes select criteria down through
@@ -813,9 +822,9 @@
<listitem>
<para>RulePlanJoins – this rule attempts to find an optimal
ordering of the joins performed in the plan, while ensuring that
- &access_patterns; dependencies are met. This rule has three main
+ <xref linkend='access_patterns'/> dependencies are met. This
rule has three main
steps. First it must determine an ordering of joins that satisfy
- the &access_patterns; present. Second it will heuristically create
+ the access patterns present. Second it will heuristically create
joins that can be pushed to the source (if a set of joins are pushed
to the source, we will not attempt to create an optimal ordering
within that set. More than likely it will be sent to the source in
@@ -914,6 +923,11 @@
choice of a hash join would also be evaluated here. Also costing
should be used to determine the strategy cost. </para>
</listitem>
+ <listitem>
+ <para>RuleDecomposeJoin - this rule perfomrs a partition-wise join
optimization on joins of <xref linkend="partitioned_union"/>.
+ The decision to decompose is based upon detecting that each side of the join is a
partitioned union (note that non-ansi joins of more than 2 tables may cause the
optimization to not detect the appropriate join).
+ The rule currently only looks for situations where at most 1 partition matches
from each side.</para>
+ </listitem>
<listitem>
<para>RuleCollapseSource - this rule removes all nodes below an
Access node and collapses them into an equivalent query that is
Modified:
trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml
===================================================================
---
trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml 2010-12-20
16:52:45 UTC (rev 2787)
@@ -27,7 +27,8 @@
</itemizedlist>
<para>A UNION ALL can define an inherently updatable view only if each of the
UNION branches is itself inherently updatable.
- A view defined by a UNION ALL though does not support inherent INSERTs.</para>
+ A view defined by a UNION ALL can support inherent INSERTs if it is a <xref
linkend="partitioned_union"/> and
+ the INSERT specifies values that belong to a single partition.</para>
<para>Any view column that is not mapped directly to a column is not updatable and
cannot be targeted by an UPDATE set
clause or be an INSERT column.</para>
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -34,6 +34,7 @@
import java.util.Set;
import java.util.TreeSet;
+import org.teiid.core.types.DataTypeManager;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.QueryCommand;
@@ -92,10 +93,10 @@
return partitions;
}
- private static boolean extractQueries(QueryCommand queryCommand, List<Query>
result) {
+ public static boolean extractQueries(QueryCommand queryCommand, List<Query>
result) {
if (queryCommand instanceof SetQuery) {
SetQuery sq = (SetQuery)queryCommand;
- if (sq.isAll() && sq.getOperation() == Operation.UNION &&
sq.getOrderBy() == null && sq.getLimit() == null) {
+ if (sq.isAll() && sq.getOperation() == Operation.UNION &&
sq.getOrderBy() == null && sq.getLimit() == null && sq.getWith() == null)
{
if (!extractQueries(sq.getLeftQuery(), result)) {
return false;
}
@@ -136,7 +137,9 @@
Map<ElementSymbol, Set<Constant>> result = new HashMap<ElementSymbol,
Set<Constant>>();
for (int i = 0; i < projected.size(); i++) {
Expression ex = SymbolMap.getExpression(projected.get(i));
-
+ if (DataTypeManager.isNonComparable(DataTypeManager.getDataTypeName(ex.getType()))) {
+ continue;
+ }
if (ex instanceof Constant) {
result.put(projectedSymbols.get(i), Collections.singleton((Constant)ex));
} else {
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -887,6 +887,7 @@
SymbolMap map = SymbolMap.createSymbolMap(group, projectCols, metadata);
node.setProperty(NodeConstants.Info.SYMBOL_MAP, map);
if (nestedCommand instanceof SetQuery) {
+ //TODO: should cache for views
Map<ElementSymbol, List<Set<Constant>>> partitionInfo =
PartitionAnalyzer.extractPartionInfo((SetQuery)nestedCommand, map.getKeys());
node.setProperty(NodeConstants.Info.PARTITION_INFO, partitionInfo);
}
Modified:
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -235,20 +235,16 @@
if(!procCommand.getGroup().isTempGroupSymbol() &&
metadata.isVirtualGroup(procCommand.getGroup().getMetadataID())) {
String plan = getPlan(metadata, procCommand.getGroup());
if (plan == null &&
!metadata.isProcedure(procCommand.getGroup().getMetadataID())) {
- UpdateInfo info = getUpdateInfo(procCommand.getGroup(), metadata);
int type = procCommand.getType();
- if ((info.isDeleteValidationError() && type == Command.TYPE_DELETE)
- || (info.isUpdateValidationError() && type == Command.TYPE_UPDATE)
- || (info.isInsertValidationError() && type == Command.TYPE_INSERT))
{
- throw new QueryResolverException("ERR.015.008.0009",
QueryPlugin.Util.getString("ERR.015.008.0009", procCommand.getGroup(),
procCommand.getClass().getSimpleName())); //$NON-NLS-1$ //$NON-NLS-2$
- }
+ //force validation
+ getUpdateInfo(procCommand.getGroup(), metadata, type);
}
return plan;
}
return null;
}
- public static UpdateInfo getUpdateInfo(GroupSymbol group, QueryMetadataInterface
metadata) throws QueryMetadataException, TeiidComponentException, QueryResolverException
{
+ public static UpdateInfo getUpdateInfo(GroupSymbol group, QueryMetadataInterface
metadata, int type) throws QueryMetadataException, TeiidComponentException,
QueryResolverException {
//if this is not a view, just return null
if(group.isTempGroupSymbol() || !metadata.isVirtualGroup(group.getMetadataID())) {
return null;
@@ -268,6 +264,18 @@
}
metadata.addToMetadataCache(group.getMetadataID(), "UpdateInfo", info);
//$NON-NLS-1$
}
+
+ if ((info.isDeleteValidationError() && type == Command.TYPE_DELETE)
+ || (info.isUpdateValidationError() && type == Command.TYPE_UPDATE)
+ || (info.isInsertValidationError() && type == Command.TYPE_INSERT)) {
+ String name = "Delete"; //$NON-NLS-1$
+ if (type == Command.TYPE_UPDATE) {
+ name = "Update"; //$NON-NLS-1$
+ } else if (type == Command.TYPE_INSERT) {
+ name = "Insert"; //$NON-NLS-1$
+ }
+ throw new QueryResolverException("ERR.015.008.0009",
QueryPlugin.Util.getString("ERR.015.008.0009", group, name)); //$NON-NLS-1$
//$NON-NLS-2$
+ }
return info;
}
@@ -283,7 +291,7 @@
// Resolve group so we can tell whether it is an update procedure
GroupSymbol group = procCommand.getGroup();
ResolverUtil.resolveGroup(group, metadata);
- procCommand.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(group,
metadata));
+ procCommand.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(group,
metadata, procCommand.getType()));
}
public static GroupSymbol addScalarGroup(String name, TempMetadataStore metadata,
GroupContext externalGroups, List symbols) {
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2010-12-17
21:22:54 UTC (rev 2786)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -2547,8 +2547,8 @@
private Insert rewriteInsert(Insert insert) throws TeiidComponentException,
TeiidProcessingException{
UpdateInfo info = insert.getUpdateInfo();
if (info != null && info.isInherentInsert()) {
- //pass through
- UpdateMapping mapping = info.findUpdateMapping(insert.getVariables(), false);
+ //TODO: update error messages
+ UpdateMapping mapping = info.findInsertUpdateMapping(insert, true);
if (mapping == null) {
throw new
QueryValidatorException(QueryPlugin.Util.getString("ValidationVisitor.nonUpdatable",
insert.getVariables())); //$NON-NLS-1$
}
@@ -2559,7 +2559,7 @@
}
insert.setVariables(mappedSymbols);
insert.setGroup(mapping.getGroup().clone());
- insert.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(insert.getGroup(),
metadata));
+ insert.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(insert.getGroup(),
metadata, Command.TYPE_INSERT));
return rewriteInsert(insert);
}
@@ -2731,7 +2731,7 @@
update.setCriteria(Criteria.combineCriteria(update.getCriteria(),
(Criteria)info.getViewDefinition().getCriteria().clone()));
}
//resolve
- update.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(update.getGroup(),
metadata));
+ update.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(update.getGroup(),
metadata, Command.TYPE_UPDATE));
return rewriteUpdate(update);
}
Query query = (Query)info.getViewDefinition().clone();
@@ -2893,7 +2893,7 @@
delete.setGroup(mapping.getGroup().clone());
//TODO: properly handle correlated references
DeepPostOrderNavigator.doVisit(delete, new
ExpressionMappingVisitor(mapping.getUpdatableViewSymbols(), true));
- delete.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(delete.getGroup(),
metadata));
+ delete.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(delete.getGroup(),
metadata, Command.TYPE_DELETE));
if (info.getViewDefinition().getCriteria() != null) {
delete.setCriteria(Criteria.combineCriteria(delete.getCriteria(),
(Criteria)info.getViewDefinition().getCriteria().clone()));
}
Modified: trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java 2010-12-17
21:22:54 UTC (rev 2786)
+++ trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -22,27 +22,31 @@
package org.teiid.query.validator;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.teiid.api.exception.query.QueryMetadataException;
+import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.util.StringUtil;
import org.teiid.language.SQLConstants;
import org.teiid.query.QueryPlugin;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.SupportConstants;
+import org.teiid.query.optimizer.relational.PartitionAnalyzer;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.lang.Command;
+import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.Query;
-import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.SetQuery;
import org.teiid.query.sql.lang.UnaryFromClause;
-import org.teiid.query.sql.lang.SetQuery.Operation;
+import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.GroupSymbol;
@@ -54,6 +58,8 @@
* the virtual group is always a <code>Query</code>. This object visits
various parts of
* this <code>Query</code> and verifies if the virtual group definition will
allows it to be
* updated.</p>
+ *
+ * TODO: add insert support based upon partitioning
*/
public class UpdateValidator {
@@ -111,8 +117,13 @@
private UpdateType insertType;
private boolean insertValidationError;
private Query view;
+ private Map<ElementSymbol, List<Set<Constant>>> partitionInfo;
private List<UpdateInfo> unionBranches = new LinkedList<UpdateInfo>();
+ public Map<ElementSymbol, List<Set<Constant>>> getPartitionInfo() {
+ return partitionInfo;
+ }
+
public boolean isSimple() {
return isSimple;
}
@@ -154,6 +165,9 @@
}
public UpdateMapping findUpdateMapping(Collection<ElementSymbol> updateCols,
boolean insert) {
+ if (updateCols.isEmpty() && this.updatableGroups.size() > 1) {
+ return null;
+ }
for (UpdateMapping entry : this.updatableGroups.values()) {
if (((insert && entry.insertAllowed) || (!insert &&
entry.updateAllowed)) &&
entry.updatableViewSymbols.keySet().containsAll(updateCols)) {
return entry;
@@ -162,6 +176,56 @@
return null;
}
+ public UpdateMapping findInsertUpdateMapping(Insert insert, boolean rewrite) throws
QueryValidatorException {
+ if (getUnionBranches().isEmpty()) {
+ return findUpdateMapping(insert.getVariables(), true);
+ }
+ if (insert.getQueryExpression() != null) {
+ //TODO: this could be done in a loop, see about adding a validation
+ throw new
QueryValidatorException(QueryPlugin.Util.getString("ValidationVisitor.insert_qe_partition",
insert.getGroup())); //$NON-NLS-1$
+ }
+ int partition = -1;
+ List<ElementSymbol> filteredColumns = new LinkedList<ElementSymbol>();
+ for (Map.Entry<ElementSymbol, List<Set<Constant>>> entry :
partitionInfo.entrySet()) {
+ int index = insert.getVariables().indexOf(entry.getKey());
+ if (index == -1) {
+ continue;
+ }
+ Expression value = (Expression)insert.getValues().get(index);
+ if (!(value instanceof Constant)) {
+ continue;
+ }
+ for (int i = 0; i < entry.getValue().size(); i++) {
+ if (entry.getValue().get(i).contains(value)) {
+ if (entry.getValue().get(i).size() == 1) {
+ filteredColumns.add(entry.getKey());
+ }
+ if (partition == -1) {
+ partition = i;
+ } else if (partition != i) {
+ throw new
QueryValidatorException(QueryPlugin.Util.getString("ValidationVisitor.insert_no_partition",
insert.getGroup(), insert.getVariables())); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ if (partition == -1) {
+ throw new
QueryValidatorException(QueryPlugin.Util.getString("ValidationVisitor.insert_no_partition",
insert.getGroup(), insert.getVariables())); //$NON-NLS-1$
+ }
+ UpdateInfo info = this;
+ if (partition > 0) {
+ info = info.getUnionBranches().get(partition - 1);
+ }
+ List<ElementSymbol> variables = rewrite?insert.getVariables():new
ArrayList<ElementSymbol>(insert.getVariables());
+ for (ElementSymbol elementSymbol : filteredColumns) {
+ int index = insert.getVariables().indexOf(elementSymbol);
+ variables.remove(index);
+ if (rewrite) {
+ insert.getValues().remove(index);
+ }
+ }
+ return info.findUpdateMapping(variables, true);
+ }
+
public Query getViewDefinition() {
return view;
}
@@ -229,15 +293,43 @@
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0013"),
true, true, true); //$NON-NLS-1$
return;
}
- if (setQuery.getOperation() != Operation.UNION || !setQuery.isAll()) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0001"),
true, true, true); //$NON-NLS-1$
- return;
+ LinkedList<Query> queries = new LinkedList<Query>();
+ if (!PartitionAnalyzer.extractQueries((SetQuery)command, queries)) {
+ handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0001"),
true, true, true); //$NON-NLS-1$
+ return;
+ }
+ Map<ElementSymbol, List<Set<Constant>>> partitions =
PartitionAnalyzer.extractPartionInfo((SetQuery)command, viewSymbols);
+ this.updateInfo.partitionInfo = partitions;
+ if (partitions.isEmpty()) {
+ handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0018"),
false, true, false); //$NON-NLS-1$
}
- validateBranch(viewSymbols, setQuery.getLeftQuery());
- validateBranch(viewSymbols, setQuery.getRightQuery());
+ boolean first = true;
+ for (Query query : queries) {
+ UpdateInfo ui = this.updateInfo;
+ if (!first) {
+ this.updateInfo = new UpdateInfo();
+ this.updateInfo.deleteType = ui.deleteType;
+ this.updateInfo.insertType = ui.insertType;
+ this.updateInfo.updateType = ui.updateType;
+ }
+ internalValidate(query, viewSymbols);
+ //accumulate the errors on the first branch - will be checked at resolve time
+ ui.deleteValidationError |= this.updateInfo.deleteValidationError;
+ ui.updateValidationError |= this.updateInfo.updateValidationError;
+ ui.insertValidationError |= this.updateInfo.insertValidationError;
+ if (!first) {
+ ui.unionBranches.add(this.updateInfo);
+ this.updateInfo = ui;
+ } else {
+ first = false;
+ }
+ }
return;
}
-
+ internalValidate(command, viewSymbols);
+ }
+
+ private void internalValidate(Command command, List<ElementSymbol> viewSymbols)
throws QueryMetadataException, TeiidComponentException {
if (!(command instanceof Query)) {
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0001"),
true, true, true); //$NON-NLS-1$
return;
@@ -251,7 +343,7 @@
}
if (query.getWith() != null) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0002"),
true, true, true); //$NON-NLS-1$
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0002"));
//$NON-NLS-1$
updateInfo.isSimple = false;
}
@@ -364,35 +456,6 @@
}
}
- private void validateBranch(List<ElementSymbol> viewSymbols,
- QueryCommand query) throws QueryMetadataException,
- TeiidComponentException {
- if (!this.updateInfo.insertValidationError) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0018"),
false, true, false); //$NON-NLS-1$
- }
- if (!this.updateInfo.isInherentDelete() && !this.updateInfo.isInherentUpdate())
{
- return; //don't bother
- }
- UpdateValidator uv = this;
- if (this.updateInfo.view != null) {
- uv = new UpdateValidator(metadata, null, null, null);
- uv.updateInfo.deleteType = this.updateInfo.deleteType;
- uv.updateInfo.insertType = this.updateInfo.insertType;
- uv.updateInfo.updateType = this.updateInfo.updateType;
- }
- uv.validate(query, viewSymbols);
- if (uv != this) {
- UpdateInfo info = uv.getUpdateInfo();
- this.updateInfo.deleteValidationError |= info.deleteValidationError;
- this.updateInfo.updateValidationError |= info.updateValidationError;
- if (info.view != null) {
- this.updateInfo.unionBranches.add(info);
- } else {
- this.updateInfo.unionBranches.addAll(info.unionBranches);
- }
- }
- }
-
private void setUpdateFlags(GroupSymbol groupSymbol) throws QueryMetadataException,
TeiidComponentException {
UpdateMapping info =
updateInfo.updatableGroups.get(groupSymbol.getCanonicalName());
Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-12-17
21:22:54 UTC (rev 2786)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -244,10 +244,13 @@
validateMultisourceInsert(obj.getGroup());
}
if (obj.getUpdateInfo() != null &&
obj.getUpdateInfo().isInherentInsert()) {
- Collection<ElementSymbol> updateCols = obj.getVariables();
- if (obj.getUpdateInfo().findUpdateMapping(updateCols, false) == null) {
-
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.nonUpdatable",
updateCols), obj); //$NON-NLS-1$
- }
+ try {
+ if (obj.getUpdateInfo().findInsertUpdateMapping(obj, false) == null) {
+ handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.nonUpdatable",
obj.getVariables()), obj); //$NON-NLS-1$
+ }
+ } catch (QueryValidatorException e) {
+ handleValidationError(e.getMessage(), obj);
+ }
}
}
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-12-17 21:22:54
UTC (rev 2786)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-12-20 16:52:45
UTC (rev 2787)
@@ -199,6 +199,8 @@
ValidationVisitor.multisource_insert = A multi-source table, {0}, cannot be used in an
INSERT with query expression or SELECT INTO statement.
ValidationVisitor.invalid_encoding = Invalid encoding: {0}.
ValidationVisitor.nonUpdatable = The specified change set {0} against an inherently
updatable view does not map to a key preserving group.
+ValidationVisitor.insert_qe_partition = Inserts with query expressions cannot be
performed against a partitioned UNION view {0}.
+ValidationVisitor.insert_no_partition = Could not determine INSERT target for a
partitioned UNION view {0} with values {1}.
ERR.015.012.0029 = INSERT, UPDATE, and DELETE not allowed on XML documents
ERR.015.012.0030 = Commands used in stored procedure language not allowed on XML
documents
ERR.015.012.0031 = Queries against XML documents can not have a GROUP By clause
Modified:
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -131,5 +131,16 @@
helpTest(userSql, viewSql, "CREATE PROCEDURE\nBEGIN\nLOOP ON (SELECT pm1.g2.e2 AS
s_0 FROM pm1.g1 INNER JOIN pm1.g2 ON g1.e1 = g2.e1 WHERE pm1.g2.e2 < 10) AS
X\nBEGIN\nDELETE FROM pm1.g2 WHERE pm1.g2.e2 = X.s_0;\nVARIABLES.ROWS_UPDATED =
(VARIABLES.ROWS_UPDATED + 1);\nEND\nEND",
dm);
}
+
+ /**
+ * Here we should use the partitioning
+ * @throws Exception
+ */
+ @Test public void testInsertPartitionedUnion() throws Exception {
+ String userSql = "insert into vm1.gx (e1, e2) values (1, 2)"; //$NON-NLS-1$
+ String viewSql = "select 1 as e1, e2 from pm1.g1 union all select 2 as e1, e2
from pm1.g2";
+ String expectedSql = "INSERT INTO pm1.g1 (e2) VALUES (2)";
+ helpTest(userSql, viewSql, expectedSql, null);
+ }
}
Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java 2010-12-17
21:22:54 UTC (rev 2786)
+++
trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java 2010-12-20
16:52:45 UTC (rev 2787)
@@ -160,19 +160,19 @@
Table vm1g5 = RealMetadataFactory.createVirtualGroup("g5", vm1,
vm1g5n1); //$NON-NLS-1$
// Create virtual elements
- List<Column> vm1g1e = RealMetadataFactory.createElements(vm1g1,
+ RealMetadataFactory.createElements(vm1g1,
new String[] { "a", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER});
- List<Column> vm1g2e = RealMetadataFactory.createElements(vm1g2,
+ RealMetadataFactory.createElements(vm1g2,
new String[] { "e1", "e2","e3", "e4"},
//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN,
DataTypeManager.DefaultDataTypes.DOUBLE });
- List<Column> vm1g3e = RealMetadataFactory.createElements(vm1g3,
+ RealMetadataFactory.createElements(vm1g3,
new String[] { "e1", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER, });
- List<Column> vm1g4e = RealMetadataFactory.createElements(vm1g4,
+ RealMetadataFactory.createElements(vm1g4,
new String[] { "e1", "e3"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.BOOLEAN });
- List<Column> vm1g5e = RealMetadataFactory.createElements(vm1g5,
+ RealMetadataFactory.createElements(vm1g5,
new String[] { "e2","e3"}, //$NON-NLS-1$ //$NON-NLS-2$
new String[] { DataTypeManager.DefaultDataTypes.INTEGER,
DataTypeManager.DefaultDataTypes.BOOLEAN });
@@ -335,6 +335,11 @@
helpTest("SELECT g1.e1, x.e2 FROM pm1.g2 x inner join pm1.g1 on (x.e1 =
g1.e1) union all select pm1.g2.e1, pm1.g2.e2 from pm1.g2",
example1(), true, false, false); //$NON-NLS-1$
}
+
+ @Test public void testParitionedUnionAll() {
+ helpTest("SELECT g1.e1, x.e2 FROM pm1.g2 x inner join pm1.g1 on (x.e1 =
g1.e1) where x.e2 in (1, 2) union all select pm1.g2.e1, pm1.g2.e2 from pm1.g2 where
pm1.g2.e2 in (3, 4)",
+ example1(), false, false, false); //$NON-NLS-1$
+ }
}