Author: shawkins
Date: 2010-11-22 23:10:27 -0500 (Mon, 22 Nov 2010)
New Revision: 2734
Added:
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java
trunk/engine/src/main/java/org/teiid/query/validator/ValidatorWarning.java
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java
trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
Removed:
trunk/engine/src/main/java/org/teiid/query/sql/util/UpdateProcedureGenerator.java
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidationVisitor.java
trunk/engine/src/test/java/org/teiid/query/sql/util/TestUpdateProcedureGenerator.java
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseJoinStrategy.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java
trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java
trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java
trunk/engine/src/main/java/org/teiid/query/resolver/command/SimpleQueryResolver.java
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateResolver.java
trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/Delete.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/Insert.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/ProcedureContainer.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/Update.java
trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java
trunk/engine/src/main/java/org/teiid/query/sql/symbol/ElementSymbol.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
trunk/engine/src/main/java/org/teiid/query/validator/ValidatorReport.java
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/query/optimizer/TestJoinPushdownRestrictions.java
trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java
trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java
trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-1349 TEIID-1368 adding better support for updatable views and ensuring that each is
a parsing reserved word
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-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -165,7 +165,7 @@
if (command instanceof QueryCommand) {
QueryCommand queryCommand = (QueryCommand)command;
final HashSet<String> names = new HashSet<String>();
- if (queryCommand.getWith() != null && !queryCommand.getWith().isEmpty()) {
+ if (queryCommand.getWith() != null) {
withList = queryCommand.getWith();
for (WithQueryCommand with : queryCommand.getWith()) {
Command subCommand = with.getCommand();
@@ -838,7 +838,7 @@
if (queryCommand.getLimit() == null) {
queryCommand.setOrderBy(null);
}
- if (merge && queryCommand.getWith() != null &&
!queryCommand.getWith().isEmpty()) {
+ if (merge && queryCommand.getWith() != null) {
//TODO: should recontext with and merge
merge = false;
}
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -33,6 +33,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.common.buffer.BufferManager;
@@ -776,7 +777,12 @@
*/
public static boolean usesKey(Collection<? extends SingleElementSymbol>
allElements, QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException {
+ return usesKey(allElements, null, metadata);
+ }
+ public static boolean usesKey(Collection<? extends SingleElementSymbol>
allElements, Set<GroupSymbol> groups, QueryMetadataInterface metadata)
+ throws QueryMetadataException, TeiidComponentException {
+
if(allElements == null || allElements.size() == 0) {
return false;
}
@@ -790,6 +796,9 @@
}
ElementSymbol element = (ElementSymbol)ex;
GroupSymbol group = element.getGroupSymbol();
+ if (groups != null && !groups.contains(group)) {
+ continue;
+ }
List<Object> elements = groupMap.get(group);
if(elements == null) {
elements = new ArrayList<Object>();
@@ -818,7 +827,7 @@
}
}
- return false;
+ return false;
}
/**
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseJoinStrategy.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseJoinStrategy.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseJoinStrategy.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -118,7 +118,7 @@
}
}
- static void separateCriteria(Collection<GroupSymbol> leftGroups,
+ public static void separateCriteria(Collection<GroupSymbol> leftGroups,
Collection<GroupSymbol> rightGroups,
List<Expression> leftExpressions,
List<Expression> rightExpressions, List<Criteria> crits,
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -49,6 +49,7 @@
import org.teiid.query.processor.relational.RelationalPlan;
import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
import org.teiid.query.processor.relational.MergeJoinStrategy.SortOption;
+import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.lang.CompareCriteria;
@@ -535,8 +536,12 @@
}
}
}
- //TODO: a better check for distinct
- return distinct || (query.getFrom().getGroups().size() == 1 &&
NewCalculateCostUtil.usesKey(expressions, metadata));
+ if (distinct) {
+ return true;
+ }
+ HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
+ ResolverUtil.findKeyPreserinvg((FromClause)query.getFrom().getClauses().get(0),
keyPreservingGroups, metadata);
+ return NewCalculateCostUtil.usesKey(expressions, keyPreservingGroups, metadata);
}
private boolean hasCorrelatedReferences(LanguageObject object, SymbolMap
correlatedReferences) {
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -608,52 +609,46 @@
/*
* Key joins must be left linear
*/
- if (sjc == SupportedJoinCriteria.KEY &&
children.get(1).getGroups().size() != 1) {
+ if (sjc == SupportedJoinCriteria.KEY &&
children.get(0).getGroups().size() != 1) {
return null;
}
if(crits != null && !crits.isEmpty()) {
- List<Object> leftIds = null;
- List<Object> rightIds = null;
- GroupSymbol leftGroup = null;
for (Criteria crit : crits) {
if (!isSupportedJoinCriteria(sjc, crit, accessModelID, metadata, capFinder,
record)) {
return null;
}
- if (sjc != SupportedJoinCriteria.KEY) {
- continue;
- }
- //key join
- //TODO: this would be much simpler if we could rely on rulechoosejoinstrategy
running first
- if (leftIds == null) {
- leftIds = new ArrayList<Object>();
- rightIds = new ArrayList<Object>();
- }
- ElementSymbol leftSymbol =
(ElementSymbol)((CompareCriteria)crit).getLeftExpression();
- ElementSymbol rightSymbol =
(ElementSymbol)((CompareCriteria)crit).getRightExpression();
- if ((children.get(0).getGroups().contains(leftSymbol.getGroupSymbol())
&& children.get(1).getGroups().contains(rightSymbol.getGroupSymbol()))
- || (children.get(1).getGroups().contains(leftSymbol.getGroupSymbol())
&& children.get(0).getGroups().contains(rightSymbol.getGroupSymbol()))) {
- boolean left =
children.get(0).getGroups().contains(leftSymbol.getGroupSymbol());
- if (leftGroup == null) {
- leftGroup = left?leftSymbol.getGroupSymbol():rightSymbol.getGroupSymbol();
- } else if
(!leftGroup.equals(left?leftSymbol.getGroupSymbol():rightSymbol.getGroupSymbol())) {
- return null;
- }
- if (left) {
- leftIds.add(leftSymbol.getMetadataID());
- rightIds.add(rightSymbol.getMetadataID());
- } else {
- rightIds.add(leftSymbol.getMetadataID());
- leftIds.add(rightSymbol.getMetadataID());
- }
- } else {
- return null;
- }
}
- if (leftIds != null &&
- !matchesForeignKey(metadata, leftIds, rightIds, leftGroup)
- && !matchesForeignKey(metadata, rightIds, leftIds,
children.get(1).getGroups().iterator().next())) {
- return null;
+ if (sjc == SupportedJoinCriteria.KEY) {
+ LinkedList<Expression> leftExpressions = new LinkedList<Expression>();
+ LinkedList<Expression> rightExpressions = new
LinkedList<Expression>();
+ RuleChooseJoinStrategy.separateCriteria(children.get(0).getGroups(),
children.get(1).getGroups(), leftExpressions, rightExpressions, crits, new
LinkedList<Criteria>());
+ ArrayList<Object> leftIds = new
ArrayList<Object>(leftExpressions.size());
+ ArrayList<Object> rightIds = new
ArrayList<Object>(rightExpressions.size());
+ for (Expression expr : leftExpressions) {
+ if (expr instanceof ElementSymbol) {
+ leftIds.add(((ElementSymbol) expr).getMetadataID());
+ }
+ }
+ GroupSymbol rightGroup = null;
+ for (Expression expr : rightExpressions) {
+ if (expr instanceof ElementSymbol) {
+ ElementSymbol es = (ElementSymbol) expr;
+ if (rightGroup == null) {
+ rightGroup = es.getGroupSymbol();
+ } else if (!rightGroup.equals(es.getGroupSymbol())) {
+ return null;
+ }
+ rightIds.add(es.getMetadataID());
+ }
+ }
+ if (rightGroup == null) {
+ return null;
+ }
+ if (!matchesForeignKey(metadata, leftIds,
rightIds, children.get(0).getGroups().iterator().next(), true)
+ && !matchesForeignKey(metadata, rightIds, leftIds, rightGroup, true)) {
+ return null;
+ }
}
} else if (sjc != SupportedJoinCriteria.ANY) {
return null; //cross join not supported
@@ -708,21 +703,18 @@
return true;
}
- /**
- * TODO: gracefully handle too much criteria
- */
- private static boolean matchesForeignKey(QueryMetadataInterface metadata,
- List<Object> leftIds, List<Object> rightIds, GroupSymbol leftGroup)
+ public static boolean matchesForeignKey(QueryMetadataInterface metadata,
+ Collection<Object> leftIds, Collection<Object> rightIds, GroupSymbol
leftGroup, boolean exact)
throws TeiidComponentException, QueryMetadataException {
Collection fks = metadata.getForeignKeysInGroup(leftGroup.getMetadataID());
for (Object fk : fks) {
List fkColumns = metadata.getElementIDsInKey(fk);
- if (!leftIds.containsAll(fkColumns) || leftIds.size() != fkColumns.size()) {
+ if ((exact && leftIds.size() != fkColumns.size()) ||
!leftIds.containsAll(fkColumns)) {
continue;
}
Object pk = metadata.getPrimaryKeyIDForForeignKeyID(fk);
List pkColumns = metadata.getElementIDsInKey(pk);
- if (rightIds.containsAll(pkColumns) && rightIds.size() == pkColumns.size()) {
+ if ((!exact || rightIds.size() == pkColumns.size()) &&
rightIds.containsAll(pkColumns)) {
return true;
}
}
Modified:
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -23,6 +23,7 @@
package org.teiid.query.resolver;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -39,6 +40,8 @@
import org.teiid.query.metadata.TempMetadataStore;
import org.teiid.query.metadata.TempMetadataID.Type;
import org.teiid.query.parser.QueryParser;
+import org.teiid.query.report.ReportItem;
+import org.teiid.query.resolver.command.UpdateProcedureResolver;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.ProcedureReservedWords;
import org.teiid.query.sql.lang.Command;
@@ -47,6 +50,9 @@
import org.teiid.query.sql.proc.CreateUpdateProcedureCommand;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.validator.UpdateValidator;
+import org.teiid.query.validator.ValidatorFailure;
+import org.teiid.query.validator.UpdateValidator.UpdateInfo;
public abstract class ProcedureContainerResolver implements CommandResolver {
@@ -127,7 +133,7 @@
*/
protected abstract String getPlan(QueryMetadataInterface metadata,
GroupSymbol group) throws TeiidComponentException,
- QueryMetadataException;
+ QueryMetadataException,
QueryResolverException;
/**
* Find all metadata defined by this command for it's children. This metadata
should be collected
@@ -201,15 +207,43 @@
throws TeiidComponentException, QueryMetadataException,
QueryResolverException {
if(!procCommand.getGroup().isTempGroupSymbol() &&
metadata.isVirtualGroup(procCommand.getGroup().getMetadataID())) {
- String plan = getPlan(metadata, procCommand.getGroup());
-
- if(plan == null) {
- 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$
- }
- return plan;
+ return getPlan(metadata, procCommand.getGroup());
}
return null;
}
+
+ public static UpdateInfo getUpdateInfo(GroupSymbol group, QueryMetadataInterface
metadata) throws QueryMetadataException, TeiidComponentException, QueryResolverException
{
+ //if this is not inherently updatable, just return null
+ if(group.isTempGroupSymbol() || !metadata.isVirtualGroup(group.getMetadataID()) || (
+ metadata.getUpdatePlan(group.getMetadataID()) != null &&
+ metadata.getDeletePlan(group.getMetadataID()) != null &&
+ metadata.getInsertPlan(group.getMetadataID()) != null)) {
+ return null;
+ }
+ UpdateInfo info = (UpdateInfo)metadata.getFromMetadataCache(group.getMetadataID(),
"UpdateInfo"); //$NON-NLS-1$
+ if (info == null) {
+
+ List<ElementSymbol> elements =
ResolverUtil.resolveElementsInGroup(group, metadata);
+
+ UpdateValidator validator = new UpdateValidator(metadata,
+ metadata.getUpdatePlan(group.getMetadataID()) == null,
+ metadata.getDeletePlan(group.getMetadataID()) == null,
+ metadata.getInsertPlan(group.getMetadataID()) == null);
+ validator.validate(UpdateProcedureResolver.getQueryTransformCmd(group, metadata),
elements);
+ info = validator.getUpdateInfo();
+ for (ReportItem item :
(Collection<ReportItem>)validator.getReport().getItems()) {
+ if (item instanceof ValidatorFailure) {
+ info.setValidationError(item.getMessage());
+ break;
+ }
+ }
+ metadata.addToMetadataCache(group.getMetadataID(), "UpdateInfo", info);
//$NON-NLS-1$
+ }
+ if (info.getValidationError() != null) {
+ throw new QueryResolverException(info.getValidationError());
+ }
+ return info;
+ }
/**
* @param metadata
@@ -223,6 +257,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));
}
public static GroupSymbol addScalarGroup(String name, TempMetadataStore metadata,
GroupContext externalGroups, List symbols) {
Modified: trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -224,7 +224,7 @@
public static boolean isXMLQuery(Query query, QueryMetadataInterface metadata)
throws TeiidComponentException, QueryMetadataException, QueryResolverException {
- if (query.getWith() != null && !query.getWith().isEmpty()) {
+ if (query.getWith() != null) {
return false;
}
Modified: trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -316,16 +316,21 @@
}
/**
+ * @throws QueryResolverException
* @see
org.teiid.query.resolver.ProcedureContainerResolver#getPlan(org.teiid.query.metadata.QueryMetadataInterface,
org.teiid.query.sql.symbol.GroupSymbol)
*/
protected String getPlan(QueryMetadataInterface metadata,
GroupSymbol group) throws TeiidComponentException,
- QueryMetadataException {
+ QueryMetadataException,
QueryResolverException {
StoredProcedureInfo storedProcedureInfo =
metadata.getStoredProcedureInfoForProcedure(group.getCanonicalName());
//if there is a query plan associated with the procedure, get it.
QueryNode plan = storedProcedureInfo.getQueryPlan();
+ if (plan.getQuery() == null) {
+ throw new QueryResolverException("ERR.015.008.0009",
QueryPlugin.Util.getString("ERR.015.008.0009", group, "Stored
Procedure")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
return plan.getQuery();
}
}
Modified:
trunk/engine/src/main/java/org/teiid/query/resolver/command/SimpleQueryResolver.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/resolver/command/SimpleQueryResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/resolver/command/SimpleQueryResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -139,7 +139,7 @@
static void resolveWith(TempMetadataAdapter metadata,
AnalysisRecord analysis, QueryCommand query) throws QueryResolverException,
TeiidComponentException {
- if (query.getWith() == null || query.getWith().isEmpty()) {
+ if (query.getWith() == null) {
return;
}
LinkedHashSet<GroupSymbol> discoveredGroups = new
LinkedHashSet<GroupSymbol>();
Modified:
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -123,7 +123,7 @@
/**
* Get the command for the transformation query that defines this virtual group.
*/
- private Command getQueryTransformCmd(GroupSymbol virtualGroup, QueryMetadataInterface
metadata)
+ public static Command getQueryTransformCmd(GroupSymbol virtualGroup,
QueryMetadataInterface metadata)
throws QueryMetadataException, QueryResolverException, TeiidComponentException {
Command transformCmd =
(Command)metadata.getFromMetadataCache(virtualGroup.getMetadataID(),
"transformation/select"); //$NON-NLS-1$
if (transformCmd != null) {
Modified: trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateResolver.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -45,6 +45,7 @@
import org.teiid.query.resolver.util.ResolverVisitor;
import org.teiid.query.sql.ProcedureReservedWords;
import org.teiid.query.sql.lang.Command;
+import org.teiid.query.sql.lang.SetClause;
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
@@ -69,6 +70,9 @@
// Resolve elements and functions
Set<GroupSymbol> groups = new HashSet<GroupSymbol>();
groups.add(update.getGroup());
+ for (SetClause clause : update.getChangeList().getClauses()) {
+ ResolverVisitor.resolveLanguageObject(clause.getSymbol(), groups, null,
metadata);
+ }
ResolverVisitor.resolveLanguageObject(update, groups,
update.getExternalGroupContexts(), metadata);
QueryResolver.resolveSubqueries(command, metadata, analysis);
}
Modified: trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -26,12 +26,15 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
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.QueryResolverException;
@@ -50,13 +53,20 @@
import org.teiid.query.metadata.TempMetadataAdapter;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.metadata.TempMetadataStore;
+import org.teiid.query.optimizer.relational.rules.RuleChooseJoinStrategy;
+import org.teiid.query.optimizer.relational.rules.RuleRaiseAccess;
import org.teiid.query.sql.LanguageObject;
+import org.teiid.query.sql.lang.Criteria;
+import org.teiid.query.sql.lang.FromClause;
+import org.teiid.query.sql.lang.JoinPredicate;
+import org.teiid.query.sql.lang.JoinType;
import org.teiid.query.sql.lang.Limit;
import org.teiid.query.sql.lang.OrderBy;
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.SubqueryContainer;
+import org.teiid.query.sql.lang.UnaryFromClause;
import org.teiid.query.sql.symbol.AbstractCaseExpression;
import org.teiid.query.sql.symbol.AggregateSymbol;
import org.teiid.query.sql.symbol.AliasSymbol;
@@ -930,5 +940,81 @@
symbol.setOutputDefinition(definition);
symbol.setOutputName(name);
}
+
+ public static void findKeyPreserinvg(FromClause clause, Set<GroupSymbol>
keyPreservingGroups, QueryMetadataInterface metadata)
+ throws TeiidComponentException, QueryMetadataException {
+ if (clause instanceof UnaryFromClause) {
+ UnaryFromClause ufc = (UnaryFromClause)clause;
+
+ if (!metadata.getUniqueKeysInGroup(ufc.getGroup().getMetadataID()).isEmpty()) {
+ keyPreservingGroups.add(ufc.getGroup());
+ }
+ }
+ if (clause instanceof JoinPredicate) {
+ JoinPredicate jp = (JoinPredicate)clause;
+ if (jp.getJoinType() == JoinType.JOIN_CROSS || jp.getJoinType() ==
JoinType.JOIN_FULL_OUTER) {
+ return;
+ }
+ HashSet<GroupSymbol> leftPk = new HashSet<GroupSymbol>();
+ findKeyPreserinvg(jp.getLeftClause(), leftPk, metadata);
+ HashSet<GroupSymbol> rightPk = new HashSet<GroupSymbol>();
+ findKeyPreserinvg(jp.getRightClause(), rightPk, metadata);
+
+ if (leftPk.isEmpty() && rightPk.isEmpty()) {
+ return;
+ }
+
+ HashSet<GroupSymbol> leftGroups = new HashSet<GroupSymbol>();
+ HashSet<GroupSymbol> rightGroups = new HashSet<GroupSymbol>();
+ jp.getLeftClause().collectGroups(leftGroups);
+ jp.getRightClause().collectGroups(rightGroups);
+
+ LinkedList<Expression> leftExpressions = new LinkedList<Expression>();
+ LinkedList<Expression> rightExpressions = new LinkedList<Expression>();
+ RuleChooseJoinStrategy.separateCriteria(leftGroups, rightGroups, leftExpressions,
rightExpressions, jp.getJoinCriteria(), new LinkedList<Criteria>());
+
+ HashMap<List<GroupSymbol>, List<HashSet<Object>>> crits = new
HashMap<List<GroupSymbol>, List<HashSet<Object>>>();
+
+ for (int i = 0; i < leftExpressions.size(); i++) {
+ Expression lexpr = leftExpressions.get(i);
+ Expression rexpr = rightExpressions.get(i);
+ if (!(lexpr instanceof ElementSymbol) || !(rexpr instanceof ElementSymbol)) {
+ continue;
+ }
+ ElementSymbol les = (ElementSymbol)lexpr;
+ ElementSymbol res = (ElementSymbol)rexpr;
+ List<GroupSymbol> tbls = Arrays.asList(les.getGroupSymbol(),
res.getGroupSymbol());
+ List<HashSet<Object>> ids = crits.get(tbls);
+ if (ids == null) {
+ ids = Arrays.asList(new HashSet<Object>(), new HashSet<Object>());
+ crits.put(tbls, ids);
+ }
+ ids.get(0).add(les.getMetadataID());
+ ids.get(1).add(res.getMetadataID());
+ }
+ if (!leftPk.isEmpty() && (jp.getJoinType() == JoinType.JOIN_INNER ||
jp.getJoinType() == JoinType.JOIN_LEFT_OUTER)) {
+ findKeyPreserving(keyPreservingGroups, leftPk, crits, true, metadata);
+ }
+ if (!rightPk.isEmpty() && (jp.getJoinType() == JoinType.JOIN_INNER ||
jp.getJoinType() == JoinType.JOIN_RIGHT_OUTER)) {
+ findKeyPreserving(keyPreservingGroups, rightPk, crits, false, metadata);
+ }
+ }
+ }
+
+ static private void findKeyPreserving(Set<GroupSymbol> keyPreservingGroups,
+ HashSet<GroupSymbol> pk,
+ HashMap<List<GroupSymbol>, List<HashSet<Object>>> crits,
boolean left, QueryMetadataInterface metadata)
+ throws TeiidComponentException, QueryMetadataException {
+ for (GroupSymbol gs : pk) {
+ for (Map.Entry<List<GroupSymbol>, List<HashSet<Object>>> entry
: crits.entrySet()) {
+ if (!entry.getKey().get(left?0:1).equals(gs)) {
+ continue;
+ }
+ if (RuleRaiseAccess.matchesForeignKey(metadata, entry.getValue().get(left?0:1),
entry.getValue().get(left?1:0), gs, false)) {
+ keyPreservingGroups.add(gs);
+ }
+ }
+ }
+ }
}
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -68,6 +68,7 @@
import org.teiid.query.optimizer.relational.rules.RulePlaceAccess;
import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria.PlannedResult;
import org.teiid.query.processor.relational.DependentValueSource;
+import org.teiid.query.resolver.ProcedureContainerResolver;
import org.teiid.query.resolver.QueryResolver;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.resolver.util.ResolverVisitor;
@@ -98,6 +99,7 @@
import org.teiid.query.sql.lang.NotCriteria;
import org.teiid.query.sql.lang.OrderBy;
import org.teiid.query.sql.lang.OrderByItem;
+import org.teiid.query.sql.lang.ProcedureContainer;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.SPParameter;
@@ -118,7 +120,9 @@
import org.teiid.query.sql.lang.WithQueryCommand;
import org.teiid.query.sql.lang.XMLTable;
import org.teiid.query.sql.lang.PredicateCriteria.Negatable;
+import org.teiid.query.sql.navigator.DeepPostOrderNavigator;
import org.teiid.query.sql.navigator.PostOrderNavigator;
+import org.teiid.query.sql.proc.AssignmentStatement;
import org.teiid.query.sql.proc.Block;
import org.teiid.query.sql.proc.CommandStatement;
import org.teiid.query.sql.proc.CreateUpdateProcedureCommand;
@@ -155,6 +159,8 @@
import org.teiid.query.sql.visitor.PredicateCollectorVisitor;
import org.teiid.query.sql.visitor.EvaluatableVisitor.EvaluationLevel;
import org.teiid.query.util.CommandContext;
+import org.teiid.query.validator.UpdateValidator.UpdateInfo;
+import org.teiid.query.validator.UpdateValidator.UpdateMapping;
import org.teiid.translator.SourceSystemFunctions;
@@ -661,7 +667,7 @@
for (Iterator<Criteria> crits = current.iterator(); crits.hasNext();) {
PlannedResult plannedResult = rmc.findSubquery(crits.next());
if (plannedResult.not || plannedResult.query == null ||
plannedResult.query.getProcessorPlan() != null
- || (plannedResult.query.getWith() != null &&
!plannedResult.query.getWith().isEmpty())) {
+ || plannedResult.query.getWith() != null) {
continue;
}
if (plannedResult.query.getCorrelatedReferences() == null) {
@@ -678,10 +684,14 @@
if (!rmc.planQuery(groups, true, plannedResult)) {
continue;
}
- if (query.getFrom().getGroups().size() != 1 ||
!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, metadata)) {
- //TODO: check for grouping or distinct in the outer query
+ HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
+ if (query.getFrom().getClauses().size() > 1) {
continue;
}
+ ResolverUtil.findKeyPreserinvg((FromClause)query.getFrom().getClauses().get(0),
keyPreservingGroups, metadata);
+ if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups,
metadata)) {
+ continue;
+ }
crits.remove();
GroupSymbol viewName = RulePlaceAccess.recontextSymbol(new GroupSymbol("X"),
names); //$NON-NLS-1$
@@ -937,14 +947,14 @@
* @param query
* @throws QueryValidatorException
*/
- private Insert rewriteSelectInto(Query query) throws TeiidComponentException,
TeiidProcessingException{
+ private Insert rewriteSelectInto(Query query) throws TeiidProcessingException{
Into into = query.getInto();
try {
List<ElementSymbol> allIntoElements =
Util.deepClone(ResolverUtil.resolveElementsInGroup(into.getGroup(), metadata),
ElementSymbol.class);
Insert insert = new Insert(into.getGroup(), allIntoElements,
Collections.emptyList());
query.setInto(null);
insert.setQueryExpression(query);
- return correctDatatypes(insert);
+ return rewriteInsert(correctDatatypes(insert));
} catch (QueryMetadataException err) {
throw new QueryValidatorException(err, err.getMessage());
} catch (TeiidComponentException err) {
@@ -2414,7 +2424,24 @@
}
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);
+ if (mapping == null) {
+ throw new
QueryValidatorException(QueryPlugin.Util.getString("ValidationVisitor.nonUpdatable",
insert.getVariables())); //$NON-NLS-1$
+ }
+ Map<ElementSymbol, ElementSymbol> symbolMap =
mapping.getUpdatableViewSymbols();
+ List<ElementSymbol> mappedSymbols = new
ArrayList<ElementSymbol>(insert.getVariables().size());
+ for (ElementSymbol symbol : (List<ElementSymbol>)insert.getVariables()) {
+ mappedSymbols.add(symbolMap.get(symbol));
+ }
+ insert.setVariables(mappedSymbols);
+ insert.setGroup(mapping.getGroup().clone());
+ insert.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(insert.getGroup(),
metadata));
+ return rewriteInsert(insert);
+ }
+
if ( insert.getQueryExpression() != null ) {
insert.setQueryExpression((QueryCommand)rewriteCommand(insert.getQueryExpression(),
true));
return correctDatatypes(insert);
@@ -2523,7 +2550,68 @@
}
}
- private Update rewriteUpdate(Update update) throws TeiidComponentException,
TeiidProcessingException{
+ private Command rewriteUpdate(Update update) throws TeiidComponentException,
TeiidProcessingException{
+ UpdateInfo info = update.getUpdateInfo();
+ if (info != null && info.isInherentUpdate()) {
+ UpdateMapping mapping =
info.findUpdateMapping(update.getChangeList().getClauseMap().keySet(), false);
+ if (mapping == null) {
+ throw new
QueryValidatorException(QueryPlugin.Util.getString("ValidationVisitor.nonUpdatable",
update.getChangeList().getClauseMap().keySet())); //$NON-NLS-1$
+ }
+ Map<ElementSymbol, ElementSymbol> symbolMap =
mapping.getUpdatableViewSymbols();
+ if (info.isSimple()) {
+ update.setGroup(mapping.getGroup().clone());
+ for (SetClause clause : update.getChangeList().getClauses()) {
+ clause.setSymbol(symbolMap.get(clause.getSymbol()));
+ }
+ //TODO: properly handle correlated references
+ DeepPostOrderNavigator.doVisit(update, new ExpressionMappingVisitor(symbolMap,
true));
+ if (info.getViewDefinition().getCriteria() != null) {
+ update.setCriteria(Criteria.combineCriteria(update.getCriteria(),
(Criteria)info.getViewDefinition().getCriteria().clone()));
+ }
+ //resolve
+ update.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(update.getGroup(),
metadata));
+ return rewriteUpdate(update);
+ }
+ Query query = (Query)info.getViewDefinition().clone();
+ query.setOrderBy(null);
+ SymbolMap expressionMapping = SymbolMap.createSymbolMap(update.getGroup(),
query.getProjectedSymbols(), metadata);
+
+ ArrayList<SingleElementSymbol> selectSymbols = new
ArrayList<SingleElementSymbol>(update.getChangeList().getClauses().size());
+ int i = 0;
+ for (SetClause clause : update.getChangeList().getClauses()) {
+ Expression ex = clause.getValue();
+ SingleElementSymbol selectSymbol = null;
+ if (!EvaluatableVisitor.willBecomeConstant(ex)) {
+ if (!(ex instanceof SingleElementSymbol)) {
+ selectSymbol = new ExpressionSymbol("expr", ex); //$NON-NLS-1$
+ } else {
+ selectSymbol = (SingleElementSymbol)ex;
+ }
+ selectSymbols.add(new AliasSymbol("s_" +i, selectSymbol)); //$NON-NLS-1$
+ ex = new ElementSymbol("s_" +i); //$NON-NLS-1$
+ }
+ clause.setSymbol(symbolMap.get(clause.getSymbol()));
+ i++;
+ }
+ query.setSelect(new Select(selectSymbols));
+ ExpressionMappingVisitor emv = new ExpressionMappingVisitor(expressionMapping.asMap(),
true);
+ PostOrderNavigator.doVisit(query.getSelect(), emv);
+
+ Criteria crit = update.getCriteria();
+ if (crit != null) {
+ PostOrderNavigator.doVisit(crit, emv);
+ query.setCriteria(Criteria.combineCriteria(query.getCriteria(), crit));
+ }
+
+ Update newUpdate = new Update();
+ newUpdate.setChangeList(update.getChangeList());
+ newUpdate.setGroup(mapping.getGroup().clone());
+
+ List<Criteria> pkCriteria = createPkCriteria(mapping, query, i);
+ newUpdate.setCriteria(Criteria.combineCriteria(newUpdate.getCriteria(), new
CompoundCriteria(pkCriteria)));
+ return createUpdateProcedure(update, query, newUpdate);
+ }
+
if (commandType == Command.TYPE_UPDATE && variables != null) {
SetClauseList newChangeList = new SetClauseList();
for (SetClause entry : update.getChangeList().getClauses()) {
@@ -2549,6 +2637,44 @@
return update;
}
+
+ private Command createUpdateProcedure(ProcedureContainer update, Query query,
+ ProcedureContainer newUpdate) throws QueryResolverException,
+ TeiidComponentException, TeiidProcessingException {
+ CreateUpdateProcedureCommand cupc = new CreateUpdateProcedureCommand();
+ Block parent = new Block();
+ Block b = new Block();
+ LoopStatement ls = new LoopStatement(b, query, "X"); //$NON-NLS-1$
+ parent.addStatement(ls);
+ b.addStatement(new CommandStatement(newUpdate));
+ AssignmentStatement as = new AssignmentStatement();
+ ElementSymbol rowsUpdate = new
ElementSymbol(ProcedureReservedWords.VARIABLES+ElementSymbol.SEPARATOR+ProcedureReservedWords.ROWS_UPDATED);
+ as.setVariable(rowsUpdate);
+ as.setExpression(new Function("+", new Expression[] {rowsUpdate, new
Constant(1)})); //$NON-NLS-1$
+ b.addStatement(as);
+ cupc.setBlock(parent);
+ cupc.setVirtualGroup(update.getGroup());
+ QueryResolver.resolveCommand(cupc, metadata);
+ return rewriteUpdateProcedure(cupc);
+ }
+
+ private List<Criteria> createPkCriteria(UpdateMapping mapping, Query query,
+ int i) throws TeiidComponentException, QueryMetadataException {
+ Object pk = metadata.getPrimaryKey(mapping.getGroup().getMetadataID());
+ if (pk == null) {
+ pk =
metadata.getUniqueKeysInGroup(mapping.getGroup().getMetadataID()).iterator().next();
+ }
+ List<Object> ids = metadata.getElementIDsInKey(pk);
+ List<Criteria> pkCriteria = new ArrayList<Criteria>(ids.size());
+ for (Object object : ids) {
+ ElementSymbol es = new ElementSymbol(mapping.getCorrelatedName().getName() +
ElementSymbol.SEPARATOR +
SingleElementSymbol.getShortName(metadata.getFullName(object)));
+ query.getSelect().addSymbol(new AliasSymbol("s_" +i, es)); //$NON-NLS-1$
+ es = new ElementSymbol(mapping.getGroup().getName() + ElementSymbol.SEPARATOR +
SingleElementSymbol.getShortName(metadata.getFullName(object)));
+ pkCriteria.add(new CompareCriteria(es, CompareCriteria.EQ, new
ElementSymbol("X.s_" + i))); //$NON-NLS-1$
+ i++;
+ }
+ return pkCriteria;
+ }
/**
* Checks variables in an expression, if the variables are INPUT variables and if
@@ -2582,7 +2708,42 @@
return true;
}
- private Delete rewriteDelete(Delete delete) throws TeiidComponentException,
TeiidProcessingException{
+ private Command rewriteDelete(Delete delete) throws TeiidComponentException,
TeiidProcessingException{
+ UpdateInfo info = delete.getUpdateInfo();
+ if (info != null && info.isInherentDelete()) {
+ UpdateMapping mapping = info.getDeleteTarget();
+ if (info.isSimple()) {
+ 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));
+ if (info.getViewDefinition().getCriteria() != null) {
+ delete.setCriteria(Criteria.combineCriteria(delete.getCriteria(),
(Criteria)info.getViewDefinition().getCriteria().clone()));
+ }
+ return rewriteDelete(delete);
+ }
+
+ Query query = (Query)info.getViewDefinition().clone();
+ query.setOrderBy(null);
+ SymbolMap expressionMapping = SymbolMap.createSymbolMap(delete.getGroup(),
query.getProjectedSymbols(), metadata);
+
+ query.setSelect(new Select());
+ ExpressionMappingVisitor emv = new ExpressionMappingVisitor(expressionMapping.asMap(),
true);
+ PostOrderNavigator.doVisit(query.getSelect(), emv);
+
+ Criteria crit = delete.getCriteria();
+ if (crit != null) {
+ PostOrderNavigator.doVisit(crit, emv);
+ query.setCriteria(Criteria.combineCriteria(query.getCriteria(), crit));
+ }
+
+ Delete newUpdate = new Delete();
+ newUpdate.setGroup(mapping.getGroup().clone());
+
+ List<Criteria> pkCriteria = createPkCriteria(mapping, query, 0);
+ newUpdate.setCriteria(Criteria.combineCriteria(newUpdate.getCriteria(), new
CompoundCriteria(pkCriteria)));
+ return createUpdateProcedure(delete, query, newUpdate);
+ }
// Rewrite criteria
Criteria crit = delete.getCriteria();
if(crit != null) {
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Delete.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Delete.java 2010-11-21 01:48:42
UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Delete.java 2010-11-23 04:10:27
UTC (rev 2734)
@@ -178,7 +178,7 @@
public Object clone() {
GroupSymbol copyGroup = null;
if(group != null) {
- copyGroup = (GroupSymbol) group.clone();
+ copyGroup = group.clone();
}
Criteria copyCrit = null;
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Insert.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Insert.java 2010-11-21 01:48:42
UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Insert.java 2010-11-23 04:10:27
UTC (rev 2734)
@@ -31,6 +31,7 @@
import org.teiid.common.buffer.TupleSource;
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.core.util.HashCodeUtil;
+import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.LanguageVisitor;
import org.teiid.query.sql.ProcedureReservedWords;
import org.teiid.query.sql.symbol.Constant;
@@ -250,20 +251,15 @@
public Object clone() {
GroupSymbol copyGroup = null;
if(group != null) {
- copyGroup = (GroupSymbol) group.clone();
+ copyGroup = group.clone();
}
- List copyVars = new LinkedList();
- Iterator iter = getVariables().iterator();
- while(iter.hasNext()) {
- ElementSymbol element = (ElementSymbol) iter.next();
- copyVars.add( element.clone() );
- }
+ List<ElementSymbol> copyVars = LanguageObject.Util.deepClone(getVariables(),
ElementSymbol.class);
List copyVals = new LinkedList();
if ( getValues() != null && getValues().size() > 0 ) {
- iter = getValues().iterator();
+ Iterator iter = getValues().iterator();
while(iter.hasNext()) {
Expression expression = (Expression) iter.next();
copyVals.add( expression.clone() );
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/ProcedureContainer.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/ProcedureContainer.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/ProcedureContainer.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -27,16 +27,19 @@
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.validator.UpdateValidator.UpdateInfo;
public abstract class ProcedureContainer extends Command {
private int updateCount = -1;
+ private UpdateInfo updateInfo;
public abstract GroupSymbol getGroup();
protected void copyMetadataState(ProcedureContainer copy) {
super.copyMetadataState(copy);
+ copy.setUpdateInfo(this.getUpdateInfo());
copy.updateCount = updateCount;
}
@@ -62,4 +65,13 @@
}
public abstract LinkedHashMap<ElementSymbol, Expression>
getProcedureParameters();
+
+ public UpdateInfo getUpdateInfo() {
+ return updateInfo;
+ }
+
+ public void setUpdateInfo(UpdateInfo updateInfo) {
+ this.updateInfo = updateInfo;
+ }
+
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java 2010-11-21 01:48:42 UTC
(rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java 2010-11-23 04:10:27 UTC
(rev 2734)
@@ -453,7 +453,7 @@
public boolean hasAggregates() {
return getGroupBy() != null
- || (getHaving() != null &&
AggregateSymbolCollectorVisitor.getAggregates(getHaving(), false).isEmpty())
+ || getHaving() != null
|| !AggregateSymbolCollectorVisitor.getAggregates(getSelect(), false).isEmpty();
}
} // END CLASS
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Update.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Update.java 2010-11-21 01:48:42
UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Update.java 2010-11-23 04:10:27
UTC (rev 2734)
@@ -224,7 +224,7 @@
Update copy = new Update();
if(group != null) {
- copy.setGroup((GroupSymbol) group.clone());
+ copy.setGroup(group.clone());
}
copy.setChangeList((SetClauseList)this.changeList.clone());
Modified: trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java 2010-11-21 01:48:42 UTC
(rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java 2010-11-23 04:10:27 UTC
(rev 2734)
@@ -110,7 +110,7 @@
* Deep clone statement to produce a new identical block.
* @return Deep clone
*/
- public Object clone() {
+ public Block clone() {
Block copy = new Block();
for (Statement statement : statements) {
copy.addStatement((Statement)statement.clone());
Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/ElementSymbol.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/ElementSymbol.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/ElementSymbol.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -44,7 +44,7 @@
private GroupSymbol groupSymbol;
private Object metadataID;
- private Class type;
+ private Class<?> type;
private boolean isExternalReference = false;
private DisplayMode displayMode = DisplayMode.OUTPUT_NAME;
@@ -160,7 +160,7 @@
* Get the type of the symbol
* @return Type of the symbol, may be null before resolution
*/
- public Class getType() {
+ public Class<?> getType() {
return this.type;
}
@@ -168,7 +168,7 @@
* Set the type of the symbol
* @param type New type
*/
- public void setType(Class type) {
+ public void setType(Class<?> type) {
this.type = type;
}
@@ -192,7 +192,7 @@
public Object clone() {
ElementSymbol copy = new ElementSymbol(getName(), getCanonical());
if(getGroupSymbol() != null) {
- copy.setGroupSymbol((GroupSymbol) getGroupSymbol().clone());
+ copy.setGroupSymbol(getGroupSymbol().clone());
}
copy.setMetadataID(getMetadataID());
copy.setType(getType());
Deleted:
trunk/engine/src/main/java/org/teiid/query/sql/util/UpdateProcedureGenerator.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/sql/util/UpdateProcedureGenerator.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/sql/util/UpdateProcedureGenerator.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -1,196 +0,0 @@
-/*
- * 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.sql.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.teiid.api.exception.query.QueryMetadataException;
-import org.teiid.core.TeiidComponentException;
-import org.teiid.query.QueryPlugin;
-import org.teiid.query.metadata.QueryMetadataInterface;
-import org.teiid.query.metadata.SupportConstants;
-import org.teiid.query.sql.ProcedureReservedWords;
-import org.teiid.query.sql.lang.*;
-import org.teiid.query.sql.navigator.PreOrderNavigator;
-import org.teiid.query.sql.proc.*;
-import org.teiid.query.sql.symbol.*;
-import org.teiid.query.validator.UpdateValidationVisitor;
-import org.teiid.query.validator.ValidatorReport;
-
-
-/**
- * Use existing query transformation to create a simple insert/update/delete procedure.
- * Only works for the virtual group that maps to single physical group.
- * No expression is allowed in SELECT statement.
- * All required elements must be specified.
- */
-public class UpdateProcedureGenerator {
-
- // constant for an Insert procedure determining the procedure type
- public static final int INSERT_PROCEDURE = 1;
-
- // constant for an Update procedure determining the procedure type
- public static final int UPDATE_PROCEDURE = 2;
-
- // constant for an Delete procedure determining the procedure type
- public static final int DELETE_PROCEDURE = 3;
-
- /**
- * Create CreateUpdateProcedureCommand for the specific virtual group.
- * @return Generated procedure or null if no procedure could be generated
- */
- public static CreateUpdateProcedureCommand createProcedure (
- int procedureType, String virtualGroup, Command queryTransformation,
QueryMetadataInterface metadata)
- throws TeiidComponentException, QueryMetadataException {
-
- // validate that a procedure can be generated
- UpdateValidationVisitor updateVisitor = new UpdateValidationVisitor(metadata);
- PreOrderNavigator.doVisit(queryTransformation, updateVisitor);
- ValidatorReport report = updateVisitor.getReport();
- if(report.hasItems()) {
- return null;
- }
-
- //the command should be a query
- Query query = (Query)queryTransformation;
- //get a list of symbols in select statement
- List selectSymbols = query.getProjectedSymbols();
-
- if(query.getFrom() == null) {
- return null;
- }
-
- GroupSymbol pGroup = query.getFrom().getGroups().iterator().next();
- String pGroupName = pGroup.getName();
- if(pGroup.getDefinition() != null) {
- pGroupName = pGroup.getDefinition();
- }
-
- //get a list of the elements in the virtual group
- List elementsInVG =
metadata.getElementIDsInGroupID(metadata.getGroupID(virtualGroup));
-
- // Create symbol for the ROWS_UPDATED special variable
- ElementSymbol rowsUpdated = new
ElementSymbol(ProcedureReservedWords.ROWS_UPDATED);
-
- CreateUpdateProcedureCommand cupc = null;
- switch(procedureType){
- case INSERT_PROCEDURE:
- {
- List variables = new ArrayList();
- List values = new ArrayList();
- mapElements(selectSymbols, elementsInVG, pGroupName, metadata, variables, values);
- Insert insert = new Insert();
- insert.setGroup(new GroupSymbol(pGroupName));
- insert.setVariables(variables);
- insert.setValues(values);
- AssignmentStatement assignStmt = new AssignmentStatement(rowsUpdated, insert);
- Block b = new Block();
- b.addStatement(assignStmt);
- cupc = new CreateUpdateProcedureCommand(b);
- break;
- }
- case UPDATE_PROCEDURE:
- {
- List variables = new ArrayList();
- List values = new ArrayList();
- mapElements(selectSymbols, elementsInVG, pGroupName, metadata, variables, values);
- Update update = new Update();
- update.setGroup(new GroupSymbol(pGroupName));
- for(int i = 0; i < variables.size(); i++){
- ElementSymbol variable = (ElementSymbol)variables.get(i);
- Expression value = (Expression)values.get(i);
- update.addChange(variable, value);
- }
- update.setCriteria(new TranslateCriteria(new CriteriaSelector()));
- AssignmentStatement assignStmt = new AssignmentStatement(rowsUpdated, update);
- Block b = new Block();
- b.addStatement(assignStmt);
- cupc = new CreateUpdateProcedureCommand(b);
- break;
- }
- case DELETE_PROCEDURE:
- {
- Delete delete = new Delete();
- delete.setGroup(new GroupSymbol(pGroupName));
- delete.setCriteria(new TranslateCriteria(new CriteriaSelector()));
- AssignmentStatement assignStmt = new AssignmentStatement(rowsUpdated, delete);
- Block b = new Block();
- b.addStatement(assignStmt);
- cupc = new CreateUpdateProcedureCommand(b);
- break;
- }
- default:
- //should not come here
- break;
- }
-
- return cupc;
- }
-
- /**
- * Virtual elements and projected symbols should match up 1-to-1. Short names
- * of both are the same. We want to build a mapping where the variables are
- * the underlying physical element and the value is the INPUT variable for the
- * virtual element.
- *
- * @param physicalElements Projected symbols from transformation query
- * @param metadata Metadata access
- * @param variables Collect each variable (physical element being updated)
- * @param values Collect each value (INPUT value for respective virtual element)
- */
- private static void mapElements(List physicalElements, List virtualElements, String
physicalGroup, QueryMetadataInterface metadata, List variables, List values)
- throws TeiidComponentException, QueryMetadataException{
-
- if(physicalElements.size()!= virtualElements.size()) {
- throw new QueryMetadataException("ERR.015.010.0018",
QueryPlugin.Util.getString("ERR.015.010.0018")); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- //match the physical group elements to the virtual group elements
- for(int i=0; i<physicalElements.size(); i++) {
- // Strip alias if necessary to get physical element
- SingleElementSymbol pSymbol = (SingleElementSymbol)physicalElements.get(i);
- if(pSymbol instanceof AliasSymbol) {
- pSymbol = ((AliasSymbol) pSymbol).getSymbol();
- }
-
- if(pSymbol instanceof ElementSymbol) {
- final Object mid = ((ElementSymbol)pSymbol).getMetadataID();
- final boolean supportsUpdate = metadata.elementSupports(mid,
SupportConstants.Element.UPDATE);
- //Only include elements that are updateable.
- if(supportsUpdate) {
- // Create properly named physical element
- String properName = metadata.getFullElementName(physicalGroup,
pSymbol.getShortName());
- variables.add(new ElementSymbol(properName));
-
- // Construct properly named INPUT variable based on short name of
virtual element
- String virtualElementName =
metadata.getFullName(virtualElements.get(i));
- String virtualElementShortName =
metadata.getShortElementName(virtualElementName);
- ElementSymbol inputElement = new
ElementSymbol(ProcedureReservedWords.INPUTS + "." + virtualElementShortName);
//$NON-NLS-1$
- values.add(inputElement);
- }
- }
- }
- }
-
-}
Modified:
trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -77,6 +77,7 @@
public class ExpressionMappingVisitor extends LanguageVisitor {
private Map symbolMap;
+ private boolean clone;
/**
* Constructor for ExpressionMappingVisitor.
@@ -85,6 +86,11 @@
public ExpressionMappingVisitor(Map symbolMap) {
this.symbolMap = symbolMap;
}
+
+ public ExpressionMappingVisitor(Map symbolMap, boolean clone) {
+ this.symbolMap = symbolMap;
+ this.clone = clone;
+ }
protected boolean createAliases() {
return true;
@@ -94,6 +100,14 @@
replaceSymbols(obj.getSymbols(), true);
}
+ public boolean isClone() {
+ return clone;
+ }
+
+ public void setClone(boolean clone) {
+ this.clone = clone;
+ }
+
@Override
public void visit(DerivedColumn obj) {
Expression original = obj.getExpression();
@@ -287,7 +301,10 @@
public Expression replaceExpression(Expression element) {
Expression mapped = (Expression) this.symbolMap.get(element);
if(mapped != null) {
- return mapped;
+ if (clone) {
+ return (Expression)mapped.clone();
+ }
+ return mapped;
}
return element;
}
Deleted:
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidationVisitor.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidationVisitor.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidationVisitor.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -1,226 +0,0 @@
-/*
- * 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.validator;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import org.teiid.core.TeiidException;
-import org.teiid.query.QueryPlugin;
-import org.teiid.query.metadata.QueryMetadataInterface;
-import org.teiid.query.metadata.SupportConstants;
-import org.teiid.query.metadata.TempMetadataID;
-import org.teiid.query.sql.lang.*;
-import org.teiid.query.sql.symbol.*;
-import org.teiid.query.sql.util.SymbolMap;
-import org.teiid.query.sql.visitor.ElementCollectorVisitor;
-
-
-/**
- * <p> This visitor is used to validate updates through virtual groups. The command
defining
- * 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>
- */
-public class UpdateValidationVisitor extends AbstractValidationVisitor {
-
- // metadata needed in validation process
- private QueryMetadataInterface metadata;
-
- // State during validation
- // collection of elementIDs defined on the SELECT clause
- private Collection elementsInSelect;
-
- /**
- * <p> This constructor initialises the visitor by setting the metadata
- * needed for validation.</p>
- * @param The metadata object needed for validation
- */
- public UpdateValidationVisitor(QueryMetadataInterface metadata) {
- super();
- this.metadata = metadata;
- this.elementsInSelect = new HashSet();
- }
-
- /**
- * This method get the metadata that this visitor uses.
- * @return The metadata object needed for validation
- */
- protected QueryMetadataInterface getMetadata() {
- return this.metadata;
- }
-
- // ############### Visitor methods for language objects ##################
-
- /**
- * <p> The command being visited should never be a
<code>SetQuery</code> object, this method reports a
- * validation error if this mehod is visited.</p>
- * @param obj The <code>SetQuery</code> object to be visited for
validation
- */
- public void visit(SetQuery obj) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0001"));
//$NON-NLS-1$
- }
-
- /**
- * <p> The command being visited should never be a
<code>StoredProcedure</code> object, this method reports a
- * validation error if this mehod is visited.</p>
- * @param obj The <code>StoredProcedure</code> object to be visited for
validation
- */
- public void visit(StoredProcedure obj) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0002"));
//$NON-NLS-1$
- }
-
- /**
- * <p> The command being visited should never be a
<code>Insert</code> object, this method reports a
- * validation error if this mehod is visited.</p>
- * @param obj The <code>Insert</code> object to be visited for
validation
- */
- public void visit(Insert obj) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0003"));
//$NON-NLS-1$
- }
-
- /**
- * <p> The command being visited should never be a
<code>Update</code> object, this method reports a
- * validation error if this mehod is visited.</p>
- * @param obj The <code>Update</code> object to be visited for
validation
- */
- public void visit(Update obj) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0004"));
//$NON-NLS-1$
- }
-
- /**
- * <p> The command being visited should never be a
<code>Delete</code> object, this method reports a
- * validation error if this mehod is visited.</p>
- * @param obj The <code>Delete</code> object to be visited for
validation
- */
- public void visit(Delete obj) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0005"));
//$NON-NLS-1$
- }
-
- /**
- * <p> This method visits the <code>Query</code> object and
verifies that
- * it has only a Select and From clause.</p>
- * @param obj The <code>Query</code> object to be visited for validation
- */
- public void visit(Query obj) {
- if((obj.getGroupBy() != null) || (obj.getHaving() != null)) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0006"));
//$NON-NLS-1$
- }
- }
-
- /**
- * <p> This method visits the <code>Select</code> and verifies that
the
- * expressions defined on it are all <code>ElementSymbol<code>s or
aliased
- * <code>ElementSymbol<code>s</p>
- * @param obj The <code>Select</code> object to be visited for
validation
- */
- public void visit(Select obj) {
-
- Iterator elementIter = obj.getProjectedSymbols().iterator();
-
- while(elementIter.hasNext()) {
- SingleElementSymbol symbol = (SingleElementSymbol) elementIter.next();
- if(symbol instanceof AliasSymbol) {
- symbol = ((AliasSymbol)symbol).getSymbol();
- }
-
- Expression ex = SymbolMap.getExpression(symbol);
-
- if (!(ex instanceof ElementSymbol || ex instanceof Constant)) {
-
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0007", symbol));
//$NON-NLS-1$
- }
- }
-
- elementsInSelect = ElementCollectorVisitor.getElements(obj, false);
- }
-
- /**
- * <p> This method visits the <code>From</code> object to validate
that
- * it has only one physical group in it. It gets the list of elements present
- * in the physical group but not specified in the Select clause and validates
- * these elements according the guidelines governing virtual group
updates.</p>
- * @param obj The <code>From</code> object to be visited for validation
- */
- public void visit(From obj) {
-
- Iterator groupIter = obj.getGroups().iterator();
-
- GroupSymbol group = (GroupSymbol) groupIter.next();
-
- if(groupIter.hasNext()) {
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0009",
obj.getGroups())); //$NON-NLS-1$
- } else {
- try {
- Object groupID = group.getMetadataID();
- if(groupID instanceof TempMetadataID) {
-
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0002"));
//$NON-NLS-1$
- } else {
- Iterator elementsInGroupIter =
getMetadata().getElementIDsInGroupID(groupID).iterator();
- // walk through all the elements in the physical group
- while(elementsInGroupIter.hasNext()) {
- Object elementID = elementsInGroupIter.next();
- ElementSymbol lookupSymbol = new
ElementSymbol(getMetadata().getFullName(elementID));
-
- // get the element that is not in the Select
- if(!elementsInSelect.contains(lookupSymbol)) {
- lookupSymbol.setMetadataID(elementID);
-
- // validate the element is not required
- validateElementNotRequired(lookupSymbol);
- }
- }
- }
- } catch(TeiidException e) {
- handleException(e);
- }
- }
- }
-
- /**
- * <p> This method validates an elements present in the group specified in the
- * FROM clause of the query but not specified in its SELECT clause, according to
- * the rules governing virtul group updates.</p>
- * @param element The <code>ElementSymbol</code> being validated
- */
- private void validateElementNotRequired(ElementSymbol element) {
-
- try {
- // checking if the elements not specified in the query are required.
- if(getMetadata().elementSupports(element.getMetadataID(),
SupportConstants.Element.NULL)) {
- return;
- } else if(getMetadata().elementSupports(element.getMetadataID(),
SupportConstants.Element.DEFAULT_VALUE)) {
- return;
- } else if(getMetadata().elementSupports(element.getMetadataID(),
SupportConstants.Element.AUTO_INCREMENT)) {
- return;
- }
-
- // this method should only be executed if the element is a required element
- // and none of cases above are true
- handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0010",
element)); //$NON-NLS-1$
- } catch(TeiidException e) {
- handleException(e);
- }
-
- }
-}
Copied: trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java (from
rev 2690,
trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidationVisitor.java)
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java
(rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -0,0 +1,328 @@
+/*
+ * 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.validator;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.teiid.api.exception.query.QueryMetadataException;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.query.QueryPlugin;
+import org.teiid.query.metadata.QueryMetadataInterface;
+import org.teiid.query.metadata.SupportConstants;
+import org.teiid.query.resolver.util.ResolverUtil;
+import org.teiid.query.sql.lang.Command;
+import org.teiid.query.sql.lang.FromClause;
+import org.teiid.query.sql.lang.Query;
+import org.teiid.query.sql.lang.UnaryFromClause;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.util.SymbolMap;
+
+/**
+ * <p> This visitor is used to validate updates through virtual groups. The command
defining
+ * 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>
+ */
+public class UpdateValidator {
+
+ public static class UpdateMapping {
+ private GroupSymbol group;
+ private GroupSymbol correlatedName;
+ private Map<ElementSymbol, ElementSymbol> updatableViewSymbols = new
HashMap<ElementSymbol, ElementSymbol>();
+ private boolean insertAllowed = false;
+ private boolean updateAllowed = false;
+
+ public Map<ElementSymbol, ElementSymbol> getUpdatableViewSymbols() {
+ return updatableViewSymbols;
+ }
+
+ public boolean isInsertAllowed() {
+ return insertAllowed;
+ }
+
+ public boolean isUpdateAllowed() {
+ return updateAllowed;
+ }
+
+ public GroupSymbol getGroup() {
+ return group;
+ }
+
+ public GroupSymbol getCorrelatedName() {
+ return correlatedName;
+ }
+ }
+
+ public static class UpdateInfo {
+ private Map<String, UpdateMapping> updatableGroups = new HashMap<String,
UpdateMapping>();
+ private boolean isSimple = true;
+ private UpdateMapping deleteTarget;
+ private String validationError;
+ private boolean inherentUpdate;
+ private boolean inherentDelete;
+ private boolean inherentInsert;
+ private Query view;
+
+ public boolean isSimple() {
+ return isSimple;
+ }
+
+ public UpdateMapping getDeleteTarget() {
+ return deleteTarget;
+ }
+
+ public Map<String, UpdateMapping> getUpdatableGroups() {
+ return updatableGroups;
+ }
+
+ public String getValidationError() {
+ return validationError;
+ }
+
+ public void setValidationError(String validationError) {
+ this.validationError = validationError;
+ }
+
+ public boolean isInherentDelete() {
+ return inherentDelete;
+ }
+
+ public boolean isInherentInsert() {
+ return inherentInsert;
+ }
+
+ public boolean isInherentUpdate() {
+ return inherentUpdate;
+ }
+
+ public UpdateMapping findUpdateMapping(Collection<ElementSymbol> updateCols,
boolean insert) {
+ for (UpdateMapping entry : getUpdatableGroups().values()) {
+ if (((insert && entry.insertAllowed) || (!insert &&
entry.updateAllowed)) &&
entry.updatableViewSymbols.keySet().containsAll(updateCols)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ public Query getViewDefinition() {
+ return view;
+ }
+
+ }
+
+ private QueryMetadataInterface metadata;
+ private ValidatorReport report = new ValidatorReport();
+ private UpdateInfo updateInfo = new UpdateInfo();
+
+ public UpdateValidator(QueryMetadataInterface qmi, boolean inherentUpdate, boolean
inherentDelete, boolean inherentInsert) {
+ this.metadata = qmi;
+ this.updateInfo.inherentDelete = inherentDelete;
+ this.updateInfo.inherentInsert = inherentInsert;
+ this.updateInfo.inherentUpdate = inherentUpdate;
+ }
+
+ public UpdateInfo getUpdateInfo() {
+ return updateInfo;
+ }
+
+ public ValidatorReport getReport() {
+ return report;
+ }
+
+ public void validate(Command command, List<ElementSymbol> viewSymbols) throws
QueryMetadataException, TeiidComponentException {
+ if (!(command instanceof Query)) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0001"));
//$NON-NLS-1$
+ return;
+ }
+
+ Query query = (Query)command;
+
+ if (query.getFrom() == null || query.getInto() != null) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0001"));
//$NON-NLS-1$
+ return;
+ }
+
+ if (query.getWith() != null) {
+
report.handleValidationWarning(QueryPlugin.Util.getString("ERR.015.012.0002"));
//$NON-NLS-1$
+ updateInfo.isSimple = false;
+ }
+
+ if (query.hasAggregates()) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0006"));
//$NON-NLS-1$
+ return;
+ }
+
+ updateInfo.view = query;
+
+ if (query.getLimit() != null) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0013"));
//$NON-NLS-1$
+ return;
+ }
+
+ if (query.getSelect().isDistinct()) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0008"));
//$NON-NLS-1$
+ return;
+ }
+
+ List<SingleElementSymbol> projectedSymbols =
query.getSelect().getProjectedSymbols();
+
+ for (int i = 0; i < projectedSymbols.size(); i++) {
+ SingleElementSymbol symbol = projectedSymbols.get(i);
+ Expression ex = SymbolMap.getExpression(symbol);
+
+ if (!metadata.elementSupports(viewSymbols.get(i).getMetadataID(),
SupportConstants.Element.UPDATE)) {
+ continue;
+ }
+ if (ex instanceof ElementSymbol) {
+ ElementSymbol es = (ElementSymbol)ex;
+ String groupName = es.getGroupSymbol().getCanonicalName();
+ UpdateMapping info = updateInfo.updatableGroups.get(groupName);
+ if (es.getGroupSymbol().getDefinition() != null) {
+ ElementSymbol clone = (ElementSymbol)es.clone();
+ clone.setName(es.getGroupSymbol().getDefinition() + ElementSymbol.SEPARATOR
+ es.getShortName());
+
clone.getGroupSymbol().setName(clone.getGroupSymbol().getNonCorrelationName());
+ clone.getGroupSymbol().setDefinition(null);
+ es = clone;
+ }
+ if (info == null) {
+ info = new UpdateMapping();
+ info.group = es.getGroupSymbol();
+ info.correlatedName = ((ElementSymbol)ex).getGroupSymbol();
+ updateInfo.updatableGroups.put(groupName, info);
+ }
+ //TODO: warn if mapped twice
+ info.updatableViewSymbols.put(viewSymbols.get(i), es);
+ } else {
+ //TODO: look for reversable widening conversions
+
+
report.handleValidationWarning(QueryPlugin.Util.getString("ERR.015.012.0007",
viewSymbols.get(i), symbol)); //$NON-NLS-1$
+ }
+ }
+
+ if (query.getFrom().getClauses().size() > 1 ||
(!(query.getFrom().getClauses().get(0) instanceof UnaryFromClause))) {
+
report.handleValidationWarning(QueryPlugin.Util.getString("ERR.015.012.0009",
query.getFrom())); //$NON-NLS-1$
+ updateInfo.isSimple = false;
+ }
+ List<GroupSymbol> allGroups = query.getFrom().getGroups();
+ HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
+
+ if (query.getFrom().getClauses().size() == 1) {
+ ResolverUtil.findKeyPreserinvg((FromClause)query.getFrom().getClauses().get(0),
keyPreservingGroups, metadata);
+ }
+
+ for (GroupSymbol groupSymbol : keyPreservingGroups) {
+ setUpdateFlags(groupSymbol);
+ }
+
+ allGroups.removeAll(keyPreservingGroups);
+ if (updateInfo.isSimple) {
+ if (!allGroups.isEmpty()) {
+ setUpdateFlags(allGroups.iterator().next());
+ }
+ } else if (this.updateInfo.inherentUpdate || this.updateInfo.inherentDelete) {
+ for (GroupSymbol groupSymbol : allGroups) {
+ UpdateMapping info = updateInfo.updatableGroups.get(groupSymbol.getCanonicalName());
+ if (info == null) {
+ continue; // not projected
+ }
+ report.handleValidationWarning(QueryPlugin.Util.getString("ERR.015.012.0004",
groupSymbol)); //$NON-NLS-1$
+ }
+ }
+
+ boolean updatable = false;
+ boolean insertable = false;
+ for (UpdateMapping info : updateInfo.updatableGroups.values()) {
+ if (info.updateAllowed) {
+ if (!updatable) {
+ this.updateInfo.deleteTarget = info;
+ } else if (!info.getGroup().equals(this.updateInfo.deleteTarget.getGroup())){
+ //TODO: warning about multiple
+ this.updateInfo.deleteTarget = null;
+ }
+ }
+ updatable |= info.updateAllowed;
+ insertable |= info.insertAllowed;
+ }
+ if ((this.updateInfo.inherentInsert && !insertable)) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0015"));
//$NON-NLS-1$
+ }
+ if (this.updateInfo.inherentUpdate && !updatable) {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0005"));
//$NON-NLS-1$
+ }
+ if (this.updateInfo.inherentDelete && this.updateInfo.deleteTarget == null)
{
+ if (this.updateInfo.isSimple) {
+ this.updateInfo.deleteTarget =
this.updateInfo.updatableGroups.values().iterator().next();
+ } else {
+
report.handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0014"));
//$NON-NLS-1$
+ }
+ }
+ }
+
+ private void setUpdateFlags(GroupSymbol groupSymbol) throws QueryMetadataException,
TeiidComponentException {
+ UpdateMapping info =
updateInfo.updatableGroups.get(groupSymbol.getCanonicalName());
+
+ if (info == null) {
+ return; // not projected
+ }
+
+ if (!metadata.groupSupports(groupSymbol.getMetadataID(),
SupportConstants.Group.UPDATE)) {
+ report.handleValidationWarning(QueryPlugin.Util.getString("ERR.015.012.0003",
groupSymbol)); //$NON-NLS-1$
+ return;
+ }
+
+ info.insertAllowed = true;
+ for (ElementSymbol es : ResolverUtil.resolveElementsInGroup(info.group, metadata)) {
+ if (!info.updatableViewSymbols.values().contains(es) &&
!validateInsertElement(es)) {
+ info.insertAllowed = false;
+ }
+ }
+ info.updateAllowed = true;
+ }
+
+ /**
+ * <p> This method validates an elements present in the group specified in the
+ * FROM clause of the query but not specified in its SELECT clause</p>
+ * @param element The <code>ElementSymbol</code> being validated
+ * @throws TeiidComponentException
+ * @throws QueryMetadataException
+ */
+ private boolean validateInsertElement(ElementSymbol element) throws
QueryMetadataException, TeiidComponentException {
+ // checking if the elements not specified in the query are required.
+ if(metadata.elementSupports(element.getMetadataID(), SupportConstants.Element.NULL)
+ || metadata.elementSupports(element.getMetadataID(),
SupportConstants.Element.DEFAULT_VALUE)
+ || metadata.elementSupports(element.getMetadataID(),
SupportConstants.Element.AUTO_INCREMENT)) {
+ return true;
+ }
+ if (this.updateInfo.inherentInsert) {
+ report.handleValidationWarning(QueryPlugin.Util.getString("ERR.015.012.0010",
element, element.getGroupSymbol())); //$NON-NLS-1$
+ }
+ return false;
+ }
+}
Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -136,6 +136,7 @@
import org.teiid.query.sql.visitor.PredicateCollectorVisitor;
import org.teiid.query.sql.visitor.SQLStringVisitor;
import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
+import org.teiid.query.validator.UpdateValidator.UpdateInfo;
import org.teiid.query.xquery.saxon.SaxonXQueryExpression;
import org.teiid.translator.SourceSystemFunctions;
@@ -198,11 +199,12 @@
public void visit(Delete obj) {
validateNoXMLUpdates(obj);
- validateHasProjectedSymbols(obj);
GroupSymbol group = obj.getGroup();
validateGroupSupportsUpdate(group);
- Criteria crit = obj.getCriteria();
- validateVirtualUpdate(group, crit);
+ if (obj.getUpdateInfo() == null || !obj.getUpdateInfo().isInherentDelete()) {
+ Criteria crit = obj.getCriteria();
+ validateVirtualUpdate(group, crit);
+ }
}
private void validateVirtualUpdate(GroupSymbol group,
@@ -252,13 +254,18 @@
public void visit(Insert obj) {
validateNoXMLUpdates(obj);
- validateHasProjectedSymbols(obj);
validateGroupSupportsUpdate(obj.getGroup());
validateInsert(obj);
if (obj.getQueryExpression() != null) {
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$
+ }
+ }
}
@Override
@@ -326,10 +333,11 @@
public void visit(Update obj) {
validateNoXMLUpdates(obj);
- validateHasProjectedSymbols(obj);
validateGroupSupportsUpdate(obj.getGroup());
validateUpdate(obj);
- validateVirtualUpdate(obj.getGroup(), obj.getCriteria());
+ if (obj.getUpdateInfo() == null || !obj.getUpdateInfo().isInherentUpdate()) {
+ validateVirtualUpdate(obj.getGroup(), obj.getCriteria());
+ }
}
public void visit(Into obj) {
@@ -902,12 +910,12 @@
protected void validateUpdate(Update update) {
try {
+ UpdateInfo info = update.getUpdateInfo();
+ boolean updatableView = info != null && info.isInherentUpdate();
+
// list of elements that are being updated
for (SetClause entry : update.getChangeList().getClauses()) {
ElementSymbol elementID = entry.getSymbol();
- if(elementID.isExternalReference()) {
-
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0058",
SQLStringVisitor.getSQLString(elementID)), elementID); //$NON-NLS-1$
- }
// Check that left side element is updatable
if(! getMetadata().elementSupports(elementID.getMetadataID(),
SupportConstants.Element.UPDATE)) {
@@ -934,24 +942,23 @@
if(((Constant)value).isNull() && !
getMetadata().elementSupports(elementID.getMetadataID(), SupportConstants.Element.NULL))
{
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0060",
SQLStringVisitor.getSQLString(elementID)), elementID); //$NON-NLS-1$
}// end of if
- } else if (!EvaluatableVisitor.willBecomeConstant(value)) {
+ } else if (!updatableView &&
getMetadata().isVirtualGroup(update.getGroup().getMetadataID()) &&
!EvaluatableVisitor.willBecomeConstant(value)) {
// If this is an update on a virtual group, verify that no elements
are in the right side
- GroupSymbol group = update.getGroup();
- if(getMetadata().isVirtualGroup(group.getMetadataID())) {
- Collection elements = ElementCollectorVisitor.getElements(value,
false);
- if(elements.size() > 0) {
- Iterator iter = elements.iterator();
- while(iter.hasNext()) {
- ElementSymbol element = (ElementSymbol) iter.next();
- if(! element.isExternalReference()) {
-
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0061",
SQLStringVisitor.getSQLString(value)), value); //$NON-NLS-1$
- }
- }
+ Collection<ElementSymbol> elements =
ElementCollectorVisitor.getElements(value, false);
+ for (ElementSymbol element : elements) {
+ if(! element.isExternalReference()) {
+
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0061",
SQLStringVisitor.getSQLString(value)), value); //$NON-NLS-1$
}
}
}
- }// end of while
- } catch(TeiidComponentException e) {
+ }
+ if (updatableView) {
+ Set<ElementSymbol> updateCols =
update.getChangeList().getClauseMap().keySet();
+ if (info.findUpdateMapping(updateCols, false) == null) {
+
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.nonUpdatable",
updateCols), update); //$NON-NLS-1$
+ }
+ }
+ } catch(TeiidException e) {
handleException(e, update);
}
Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidatorReport.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidatorReport.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidatorReport.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -27,6 +27,7 @@
import org.teiid.query.QueryPlugin;
import org.teiid.query.report.ActivityReport;
+import org.teiid.query.sql.LanguageObject;
public class ValidatorReport extends ActivityReport {
@@ -73,5 +74,21 @@
public String toString() {
return this.getFailureMessage();
}
+
+ public void handleValidationError(String message) {
+ this.addItem(new ValidatorFailure(message));
+ }
+ public void handleValidationError(String message, LanguageObject invalidObj) {
+ this.addItem(new ValidatorFailure(message, invalidObj));
+ }
+
+ public void handleValidationError(String message, Collection invalidObjs) {
+ this.addItem(new ValidatorFailure(message, invalidObjs));
+ }
+
+ public void handleValidationWarning(String message) {
+ this.addItem(new ValidatorWarning(message));
+ }
+
}
Added: trunk/engine/src/main/java/org/teiid/query/validator/ValidatorWarning.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidatorWarning.java
(rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidatorWarning.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -0,0 +1,84 @@
+/*
+ * 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.validator;
+
+import java.util.*;
+
+import org.teiid.query.report.ReportItem;
+import org.teiid.query.sql.LanguageObject;
+
+public class ValidatorWarning extends ReportItem {
+
+ private static final long serialVersionUID = 3991298598581344564L;
+
+ public static final String VALIDATOR_WARNING = "ValidatorWarning";
//$NON-NLS-1$
+
+ // Don't want to pass this around, so make it transient
+ private transient Collection invalidObjects;
+
+ public ValidatorWarning(String description) {
+ super(VALIDATOR_WARNING);
+ setMessage(description);
+ }
+
+ public ValidatorWarning(String description, LanguageObject object) {
+ super(VALIDATOR_WARNING);
+ setMessage(description);
+ this.invalidObjects = new ArrayList(1);
+ this.invalidObjects.add(object);
+ }
+
+ public ValidatorWarning(String description, Collection objects) {
+ super(VALIDATOR_WARNING);
+ setMessage(description);
+ this.invalidObjects = new ArrayList(objects);
+ }
+
+ /**
+ * Get count of invalid objects.
+ * @return Count of invalid objects
+ */
+ public int getInvalidObjectCount() {
+ if(this.invalidObjects == null) {
+ return 0;
+ }
+ return this.invalidObjects.size();
+ }
+
+ /**
+ * Get the objects that failed validation. The collection may be null.
+ * @return Invalid objects, may be null
+ */
+ public Collection getInvalidObjects() {
+ return this.invalidObjects;
+ }
+
+ /**
+ * Return description
+ * @return Description of failure
+ */
+ public String toString() {
+ return getMessage();
+ }
+
+}
Property changes on:
trunk/engine/src/main/java/org/teiid/query/validator/ValidatorWarning.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-11-21 01:48:42
UTC (rev 2733)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-11-23 04:10:27
UTC (rev 2734)
@@ -165,17 +165,21 @@
# util (011)
# validator (012)
-ERR.015.012.0001 = The query defining an updatable virtual group cannot be a UNION query
-ERR.015.012.0002 = The query defining an updatable virtual group cannot be a stored query
or stored procedure execution
-ERR.015.012.0003 = The query defining an updatable virtual group cannot be an INSERT
-ERR.015.012.0004 = The query defining an updatable virtual group cannot be an UPDATE
-ERR.015.012.0005 = The query defining an updatable virtual group cannot be a DELETE
-ERR.015.012.0006 = The query defining an updatable virtual group should not use GROUP BY
or HAVING.
-ERR.015.012.0007 = The query defining an updatable virtual group cannot use a
non-constant, non-column reference expressions in its SELECT clause {0}.
-ERR.015.012.0009 = The query defining an updatable virtual group cannot have more than
one group in its FROM clause {0}
-ERR.015.012.0010 = The query defining an updatable simple virtual group should select all
the required elements in its FROM clause {0}
+ERR.015.012.0001 = The query defining an updatable view must be a simple query with a
FROM clause.
+ERR.015.012.0002 = The query defining an updatable view has a WITH clause, pass-through
processing will not be used for UPDATE/DELETE operations.
+ERR.015.012.0003 = The query defining an updatable view projects a column from a
non-updatable group {0}.
+ERR.015.012.0004 = The query defining an updatable view has a non key preserving join
group {0}, which cannot be targeted by UPDATE/DELETE operations.
+ERR.015.012.0005 = The query defining an updatable view has no valid target for UPDATEs.
+ERR.015.012.0006 = The query defining an updatable view should not use aggregates or
grouping.
+ERR.015.012.0007 = The query defining an updatable view has a non-updatable expression
{0} for view column {1}.
+ERR.015.012.0008 = The query defining an updatable view cannot use SELECT DISTINCT.
+ERR.015.012.0009 = The query defining an updatable view has a non-simple FROM clause,
pass-through processing will not be used for UPDATE/DELETE operations.
+ERR.015.012.0010 = The query defining an updatable view does not project the column {0},
which is required to make {1} a target of INSERT operations.
ERR.015.012.0011 = There must be exactly one projected symbol in the subcommand of an IN
clause.
ERR.015.012.0012 = An AssignmentStatement cannot change the value of a {0} or {1}
variable.
+ERR.015.012.0013 = The query defining an updatable virtual group cannot use LIMIT.
+ERR.015.012.0014 = The non-simple query defining an updatable view does not have a valid
key preserving delete target.
+ERR.015.012.0015 = The query defining an updatable view has no valid target for INSERTs.
ERR.015.012.0016 = Variable {0} not assigned any value in this procedure.
ERR.015.012.0017 = Variables declared the procedure''s DeclareStatement cannot be
one of the special variables: {0}, {1} and {2}.
ERR.015.012.0019 = TranslateCriteria cannot be used in on an if or while statement.
@@ -195,6 +199,7 @@
ValidationVisitor.multisource_insert = A multi-source table, {0}, cannot be used in an
INSERT with query expression or SELECT INTO statement.
ValidationVisitor.virtual_update_subquery = Subqueries are not allowed in the criteria
for a virtual UPDATE/DELETE: {0}
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.
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
@@ -214,10 +219,9 @@
ERR.015.012.0053 = Element in the group {0}, for which value is not specified in the
insert command is neither nullable nor has a default value: {1}
ERR.015.012.0054 = Column variables do not reference columns on group "{0}":
{1}
ERR.015.012.0055 = Element {0} does not allow nulls.
-ERR.015.012.0058 = Left side of update expression may not be a variable or a reference to
an external element: {0}
ERR.015.012.0059 = Left side of update expression must be an element that supports
update: {0}
ERR.015.012.0060 = Element {0} does not allow nulls.
-ERR.015.012.0061 = Update values must be a constant expression. The expression
''{0}'' cannot be evaluated to a constant.
+ERR.015.012.0061 = Views using update procedures must have update values that are
constant expressiosn. The expression ''{0}'' cannot be evaluated to a
constant.
ERR.015.012.0062 = Elements cannot appear more than once in a SET or USING clause. The
following elements are duplicated: {0}
ERR.015.012.0063 = Multiple failures occurred during validation:
ERR.015.012.0064 = Validation succeeded
Modified:
trunk/engine/src/test/java/org/teiid/query/optimizer/TestJoinPushdownRestrictions.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/optimizer/TestJoinPushdownRestrictions.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/test/java/org/teiid/query/optimizer/TestJoinPushdownRestrictions.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -87,6 +87,19 @@
new String[] {"SELECT g_0.e2, g_1.e2 FROM pm1.g1 AS g_0, pm1.g2 AS g_1
WHERE g_0.e2 = g_1.e2"}, capFinder,
TestOptimizer.ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
}
+ @Test public void testKeyRestriction1() throws Exception {
+ String sql = "select a.e1, b.e1 from pm4.g1 a inner join pm4.g2 b on (a.e1 = b.e1
and a.e2 = b.e2) left outer join pm4.g1 c on (c.e1 = b.e1 and c.e2 = b.e2)";
//$NON-NLS-1$
+
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ caps.setCapabilitySupport(Capability.QUERY_FROM_JOIN_SELFJOIN, true);
+ caps.setSourceProperty(Capability.JOIN_CRITERIA_ALLOWED,
SupportedJoinCriteria.KEY);
+ capFinder.addCapabilities("pm4", caps); //$NON-NLS-1$
+
+ TestOptimizer.helpPlan(sql, FakeMetadataFactory.example4(),
+ new String[] {"SELECT g_1.e1 AS c_0, g_1.e2 AS c_1, g_0.e1 AS c_2 FROM
pm4.g1 AS g_0, pm4.g2 AS g_1 WHERE (g_0.e1 = g_1.e1) AND (g_0.e2 = g_1.e2) ORDER BY c_0,
c_1", "SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm4.g1 AS g_0 ORDER BY c_0,
c_1"}, capFinder, TestOptimizer.ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
//$NON-NLS-2$
+ }
+
@Test public void testKeyPasses() throws Exception {
String sql = "select a.e1, b.e1 from pm4.g1 a, pm4.g2 b where a.e1 = b.e1 and a.e2
= b.e2"; //$NON-NLS-1$
Added:
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java
(rev 0)
+++
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -0,0 +1,123 @@
+/*
+ * 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.processor;
+
+import static org.teiid.query.processor.TestProcessor.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.teiid.query.metadata.TransformationMetadata;
+import org.teiid.query.optimizer.TestOptimizer;
+import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
+import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
+import org.teiid.query.rewriter.TestQueryRewriter;
+import org.teiid.query.sql.lang.Command;
+import org.teiid.query.util.CommandContext;
+import org.teiid.query.validator.TestUpdateValidator;
+import org.teiid.translator.SourceSystemFunctions;
+
+@SuppressWarnings("nls")
+public class TestInherintlyUpdatableViews {
+
+ @Test public void testUpdatePassThrough() throws Exception {
+ String userSql = "update vm1.gx set e1 = e2"; //$NON-NLS-1$
+ String viewSql = "select * from pm1.g1 where e3 < 5";
+ String expectedSql = "UPDATE pm1.g1 SET e1 = pm1.g1.e2 WHERE e3 < 5";
+ helpTest(userSql, viewSql, expectedSql, null);
+ }
+
+ private void helpTest(String userSql, String viewSql, String expectedSql,
ProcessorDataManager dm)
+ throws Exception {
+ TransformationMetadata metadata = TestUpdateValidator.example1();
+ TestUpdateValidator.createView(viewSql, metadata, "gx");
+ Command command = TestQueryRewriter.helpTestRewriteCommand(userSql, expectedSql,
metadata);
+
+ if (dm != null) {
+ CommandContext context = createCommandContext();
+ BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ caps.setFunctionSupport(SourceSystemFunctions.CONVERT, true);
+ ProcessorPlan plan = helpGetPlan(command, metadata, new
DefaultCapabilitiesFinder(caps), context);
+ List[] expected = new List[] {Arrays.asList(1)};
+ helpProcess(plan, context, dm, expected);
+ }
+ }
+
+ @Test public void testUpdatePassThroughWithAlias() throws Exception {
+ String userSql = "update vm1.gx set e1 = e2"; //$NON-NLS-1$
+ String viewSql = "select * from pm1.g1 as x where e3 < 5";
+ String expectedSql = "UPDATE pm1.g1 SET e1 = pm1.g1.e2 WHERE e3 < 5";
+ helpTest(userSql, viewSql, expectedSql, null);
+ }
+
+ @Test public void testDeletePassThrough() throws Exception {
+ String userSql = "delete from vm1.gx where e1 = e2"; //$NON-NLS-1$
+ String viewSql = "select * from pm1.g1 where e3 < 5";
+ String expectedSql = "DELETE FROM pm1.g1 WHERE (pm1.g1.e1 = pm1.g1.e2) AND
(e3 < 5)";
+ helpTest(userSql, viewSql, expectedSql, null);
+ }
+
+ @Test public void testInsertPassThrough() throws Exception {
+ String userSql = "insert into vm1.gx (e1) values (1)"; //$NON-NLS-1$
+ String viewSql = "select * from pm1.g1 where e3 < 5";
+ String expectedSql = "INSERT INTO pm1.g1 (pm1.g1.e1) VALUES
('1')";
+ helpTest(userSql, viewSql, expectedSql, null);
+ }
+
+ /**
+ * Here we should be able to figure out that we can pass through the join
+ * @throws Exception
+ */
+ @Test public void testInsertPassThrough1() throws Exception {
+ String userSql = "insert into vm1.gx (e1) values (1)"; //$NON-NLS-1$
+ String viewSql = "select g2.* from pm1.g1 inner join pm1.g2 on g1.e1 =
g2.e1";
+ String expectedSql = "INSERT INTO pm1.g2 (pm1.g2.e1) VALUES
('1')";
+ helpTest(userSql, viewSql, expectedSql, null);
+ }
+
+ @Test public void testUpdateComplex() throws Exception {
+ String userSql = "update vm1.gx set e1 = e2 where e3 is null"; //$NON-NLS-1$
+ String viewSql = "select g2.* from pm1.g1 inner join pm1.g2 on g1.e1 =
g2.e1";
+
+ HardcodedDataManager dm = new HardcodedDataManager();
+ dm.addData("SELECT g_1.e2, g_1.e2 FROM pm1.g1 AS g_0, pm1.g2 AS g_1 WHERE
(g_0.e1 = g_1.e1) AND (g_1.e3 IS NULL)", new List[] {Arrays.asList(1, 1)});
+ dm.addData("UPDATE pm1.g2 SET e1 = pm1.g2.e2 WHERE pm1.g2.e2 = 1", new
List[] {Arrays.asList(1)});
+
+ helpTest(userSql, viewSql, "CREATE PROCEDURE\nBEGIN\nLOOP ON (SELECT pm1.g2.e2 AS
s_0, pm1.g2.e2 AS s_1 FROM pm1.g1 INNER JOIN pm1.g2 ON g1.e1 = g2.e1 WHERE pm1.g2.e3 IS
NULL) AS X\nBEGIN\nUPDATE pm1.g2 SET e1 = pm1.g2.e2 WHERE pm1.g2.e2 =
X.s_1;\nVARIABLES.ROWS_UPDATED = (VARIABLES.ROWS_UPDATED + 1);\nEND\nEND",
+ dm);
+ }
+
+ @Test public void testDeleteComplex() throws Exception {
+ String userSql = "delete from vm1.gx where e2 < 10"; //$NON-NLS-1$
+ String viewSql = "select g2.* from pm1.g1 inner join pm1.g2 on g1.e1 =
g2.e1";
+
+ HardcodedDataManager dm = new HardcodedDataManager();
+ dm.addData("SELECT g_1.e2 FROM pm1.g1 AS g_0, pm1.g2 AS g_1 WHERE (g_0.e1 =
g_1.e1) AND (g_1.e2 < 10)", new List[] {Arrays.asList(2)});
+ dm.addData("DELETE FROM pm1.g2 WHERE pm1.g2.e2 = 2", new List[]
{Arrays.asList(1)});
+
+ 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);
+ }
+
+}
Property changes on:
trunk/engine/src/test/java/org/teiid/query/processor/TestInherintlyUpdatableViews.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -2573,24 +2573,6 @@
helpResolveException(sql);
}
- @Test public void testUpdateError() {
- String userUpdateStr = "UPDATE vm1.g2 SET e1='x'";
//$NON-NLS-1$
-
- helpResolveException(userUpdateStr, metadata, "Error Code:ERR.015.008.0009
Message:Update is not allowed on the virtual group vm1.g2: no Update procedure was
defined."); //$NON-NLS-1$
- }
-
- @Test public void testInsertError() {
- String userUpdateStr = "INSERT into vm1.g2 (e1) values ('x')";
//$NON-NLS-1$
-
- helpResolveException(userUpdateStr, metadata, "Error Code:ERR.015.008.0009
Message:Insert is not allowed on the virtual group vm1.g2: no Insert procedure was
defined."); //$NON-NLS-1$
- }
-
- @Test public void testDeleteError() {
- String userUpdateStr = "DELETE from vm1.g2 where e1='x'";
//$NON-NLS-1$
-
- helpResolveException(userUpdateStr, metadata, "Error Code:ERR.015.008.0009
Message:Delete is not allowed on the virtual group vm1.g2: no Delete procedure was
defined."); //$NON-NLS-1$
- }
-
@Test public void testResolveXMLSelect() {
String procedure = "CREATE VIRTUAL PROCEDURE "; //$NON-NLS-1$
procedure = procedure + "BEGIN\n"; //$NON-NLS-1$
@@ -3064,5 +3046,19 @@
@Test public void testWithNameMatchesFrom() {
helpResolve("with x as (TABLE pm1.g1) SELECT * from (TABLE x) x");
}
+
+ // variables cannot be used among insert elements
+ @Test(expected=QueryResolverException.class) public void
testCreateUpdateProcedure23() throws Exception {
+ String procedure = "CREATE PROCEDURE "; //$NON-NLS-1$
+ procedure = procedure + "BEGIN\n"; //$NON-NLS-1$
+ procedure = procedure + "DECLARE integer var1;\n"; //$NON-NLS-1$
+ procedure = procedure + "Update pm1.g1 SET pm1.g1.e2 =1 , var1 = 2;\n";
//$NON-NLS-1$
+ procedure = procedure + "ROWS_UPDATED =0;\n"; //$NON-NLS-1$
+ procedure = procedure + "END\n"; //$NON-NLS-1$
+
+ String userQuery = "UPDATE vm1.g3 SET x='x' where e3= 1";
//$NON-NLS-1$
+
+ helpResolveUpdateProcedure(procedure, userQuery);
+ }
}
\ No newline at end of file
Deleted:
trunk/engine/src/test/java/org/teiid/query/sql/util/TestUpdateProcedureGenerator.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/sql/util/TestUpdateProcedureGenerator.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/test/java/org/teiid/query/sql/util/TestUpdateProcedureGenerator.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -1,384 +0,0 @@
-/*
- * 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.sql.util;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.teiid.client.metadata.ParameterInfo;
-import org.teiid.core.TeiidException;
-import org.teiid.core.types.DataTypeManager;
-import org.teiid.query.mapping.relational.QueryNode;
-import org.teiid.query.metadata.QueryMetadataInterface;
-import org.teiid.query.parser.QueryParser;
-import org.teiid.query.resolver.QueryResolver;
-import org.teiid.query.sql.lang.Command;
-import org.teiid.query.sql.proc.CreateUpdateProcedureCommand;
-import org.teiid.query.sql.util.UpdateProcedureGenerator;
-import org.teiid.query.unittest.FakeMetadataFacade;
-import org.teiid.query.unittest.FakeMetadataFactory;
-import org.teiid.query.unittest.FakeMetadataObject;
-import org.teiid.query.unittest.FakeMetadataStore;
-
-import junit.framework.TestCase;
-
-
-/**
-
- */
-public class TestUpdateProcedureGenerator extends TestCase{
-
- public TestUpdateProcedureGenerator(String name) {
- super(name);
- }
-
- // ################################## TEST HELPERS ################################
-
- private void helpTest(int procedureType, String vGroup, String sql,
QueryMetadataInterface md, String expectedProc) {
- try {
- Command command = QueryParser.getQueryParser().parseCommand(sql);
- QueryResolver.resolveCommand(command, md);
-
- CreateUpdateProcedureCommand actualProc =
UpdateProcedureGenerator.createProcedure(procedureType, vGroup, command, md);
- if (expectedProc == null) {
- assertNull(actualProc);
- } else {
- assertNotNull(actualProc);
- assertEquals("Didn't get expected generated procedure",
expectedProc, actualProc.toString()); //$NON-NLS-1$
- QueryParser.getQueryParser().parseCommand(actualProc.toString());
- }
- } catch (TeiidException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static FakeMetadataFacade example1() {
- return example1(true);
- }
-
- public static FakeMetadataFacade example1(boolean allUpdatable) {
- // Create models
- FakeMetadataObject pm1 = FakeMetadataFactory.createPhysicalModel("pm1");
//$NON-NLS-1$
- FakeMetadataObject vm1 = FakeMetadataFactory.createVirtualModel("vm1");
//$NON-NLS-1$
-
- // Create physical groups
- FakeMetadataObject pm1g1 = FakeMetadataFactory.createPhysicalGroup("pm1.g1",
pm1); //$NON-NLS-1$
- FakeMetadataObject pm1g2 = FakeMetadataFactory.createPhysicalGroup("pm1.g2",
pm1); //$NON-NLS-1$
- FakeMetadataObject pm1g3 =
FakeMetadataFactory.createPhysicalGroup("pm1.g3", pm1); //$NON-NLS-1$
-
- // Create physical elements
- List pm1g1e = FakeMetadataFactory.createElements(pm1g1,
- 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 });
- if (!allUpdatable) {
- ((FakeMetadataObject)pm1g1e.get(0)).putProperty(FakeMetadataObject.Props.UPDATE,
Boolean.FALSE);
- }
-
- List pm1g2e = FakeMetadataFactory.createElements(pm1g2,
- 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 pm1g3e = FakeMetadataFactory.createElements(pm1g3,
- 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 });
- ((FakeMetadataObject)pm1g3e.get(0)).putProperty(FakeMetadataObject.Props.NULL,
Boolean.FALSE);
-
((FakeMetadataObject)pm1g3e.get(0)).putProperty(FakeMetadataObject.Props.DEFAULT_VALUE,
null);
-
- ((FakeMetadataObject)pm1g3e.get(1)).putProperty(FakeMetadataObject.Props.NULL,
Boolean.FALSE);
-
((FakeMetadataObject)pm1g3e.get(1)).putProperty(FakeMetadataObject.Props.AUTO_INCREMENT,
Boolean.TRUE);
-
((FakeMetadataObject)pm1g3e.get(1)).putProperty(FakeMetadataObject.Props.DEFAULT_VALUE,
null);
-
- ((FakeMetadataObject)pm1g3e.get(2)).putProperty(FakeMetadataObject.Props.NULL,
Boolean.FALSE);
-
((FakeMetadataObject)pm1g3e.get(2)).putProperty(FakeMetadataObject.Props.DEFAULT_VALUE,
"xyz"); //$NON-NLS-1$
-
- // Create virtual groups
- QueryNode vm1g1n1 = new QueryNode("vm1.g1", "SELECT e1 as a, e2 FROM
pm1.g1 WHERE e3 > 5"); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject vm1g1 =
FakeMetadataFactory.createUpdatableVirtualGroup("vm1.g1", vm1, vm1g1n1);
//$NON-NLS-1$
- QueryNode vm1g2n1 = new QueryNode("vm1.g2", "SELECT e1, e2, e3, e4 FROM
pm1.g2 WHERE e3 > 5"); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject vm1g2 =
FakeMetadataFactory.createUpdatableVirtualGroup("vm1.g2", vm1, vm1g2n1);
//$NON-NLS-1$
- QueryNode vm1g3n1 = new QueryNode("vm1.g3", "SELECT e1, e3 FROM
pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject vm1g3 =
FakeMetadataFactory.createUpdatableVirtualGroup("vm1.g3", vm1, vm1g3n1);
//$NON-NLS-1$
- QueryNode vm1g4n1 = new QueryNode("vm1.g4", "SELECT e1, e2 FROM
pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject vm1g4 =
FakeMetadataFactory.createUpdatableVirtualGroup("vm1.g4", vm1, vm1g4n1);
//$NON-NLS-1$
- QueryNode vm1g5n1 = new QueryNode("vm1.g5", "SELECT e2, e3 FROM
pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject vm1g5 =
FakeMetadataFactory.createUpdatableVirtualGroup("vm1.g5", vm1, vm1g5n1);
//$NON-NLS-1$
-
- // Create virtual elements
- List vm1g1e = FakeMetadataFactory.createElements(vm1g1,
- new String[] { "a", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
- new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER});
- List vm1g2e = FakeMetadataFactory.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 vm1g3e = FakeMetadataFactory.createElements(vm1g3,
- new String[] { "e1", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
- new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER, });
- List vm1g4e = FakeMetadataFactory.createElements(vm1g4,
- new String[] { "e1", "e3"}, //$NON-NLS-1$ //$NON-NLS-2$
- new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.BOOLEAN });
- List vm1g5e = FakeMetadataFactory.createElements(vm1g5,
- new String[] { "e2","e3"}, //$NON-NLS-1$ //$NON-NLS-2$
- new String[] { DataTypeManager.DefaultDataTypes.INTEGER,
DataTypeManager.DefaultDataTypes.BOOLEAN });
-
- // Stored queries
- FakeMetadataObject rs1 = FakeMetadataFactory.createResultSet("pm1.rs1",
pm1, new String[] { "e1", "e2" }, new String[] {
DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER });
//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- FakeMetadataObject rs1p1 = FakeMetadataFactory.createParameter("ret",
1, ParameterInfo.RESULT_SET, DataTypeManager.DefaultDataTypes.OBJECT, rs1);
//$NON-NLS-1$
- QueryNode sq1n1 = new QueryNode("pm1.sq1", "CREATE VIRTUAL
PROCEDURE BEGIN SELECT e1, e2 FROM pm1.g1; END"); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject sq1 =
FakeMetadataFactory.createVirtualProcedure("pm1.sq1", pm1, Arrays.asList(new
FakeMetadataObject[] { rs1p1 }), sq1n1); //$NON-NLS-1$
-
- // Add all objects to the store
- FakeMetadataStore store = new FakeMetadataStore();
- store.addObject(pm1);
- store.addObject(pm1g1);
- store.addObjects(pm1g1e);
- store.addObject(pm1g2);
- store.addObjects(pm1g2e);
- store.addObject(pm1g3);
- store.addObjects(pm1g3e);
-
- store.addObject(vm1);
- store.addObject(vm1g1);
- store.addObjects(vm1g1e);
- store.addObject(vm1g2);
- store.addObjects(vm1g2e);
- store.addObject(vm1g3);
- store.addObjects(vm1g3e);
- store.addObject(vm1g4);
- store.addObjects(vm1g4e);
- store.addObject(vm1g5);
- store.addObjects(vm1g5e);
-
- store.addObject(rs1);
- store.addObject(sq1);
-
- // Create the facade from the store
- return new FakeMetadataFacade(store);
- }
-
- //actual tests
- public void testCreateInsertCommand(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "select e1 as a, e2 from pm1.g1 where e4 > 5",
//$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g1 (pm1.g1.e1, pm1.g1.e2)
VALUES (INPUTS.a, INPUTS.e2);\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND");
//$NON-NLS-1$
- }
-
- public void testCreateInsertCommand2(){ //put a constant in select statement
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "select e1 as a, 5 from pm1.g1 where e4 > 5", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g1 (pm1.g1.e1) VALUES
(INPUTS.a);\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
- public void testCreateInsertCommand3(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g2", //$NON-NLS-1$
- "select * from pm1.g2 where e4 > 5", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g2 (pm1.g2.e1, pm1.g2.e2,
pm1.g2.e3, pm1.g2.e4) VALUES (INPUTS.e1, INPUTS.e2, INPUTS.e3, INPUTS.e4);\nROWS_UPDATED =
VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
- public void testCreateInsertCommand4(){ //test group alias
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g2", //$NON-NLS-1$
- "select * from pm1.g2 as g_alias", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g2 (pm1.g2.e1, pm1.g2.e2, pm1.g2.e3,
pm1.g2.e4) VALUES (INPUTS.e1, INPUTS.e2, INPUTS.e3, INPUTS.e4);\nROWS_UPDATED =
VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
- public void testCreateInsertCommand5(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "select e1 as a, e2 from pm1.g1 as g_alias where e4 > 5",
//$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g1 (pm1.g1.e1, pm1.g1.e2) VALUES
(INPUTS.a, INPUTS.e2);\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
- public void testCreateUpdateCommand(){
- helpTest(UpdateProcedureGenerator.UPDATE_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "select e1 as a, e2 from pm1.g1 where e4 > 5",
//$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nUPDATE pm1.g1 SET e1 = INPUTS.a, e2 =
INPUTS.e2 WHERE TRANSLATE CRITERIA;\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND");
//$NON-NLS-1$
- }
-
- public void testCreateDeleteCommand(){
- helpTest(UpdateProcedureGenerator.DELETE_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "select e1 as a, e2 from pm1.g1 where e4 > 5",
//$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nDELETE FROM pm1.g1 WHERE TRANSLATE
CRITERIA;\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
- public void testCreateInsertCommand1_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT pm1.g1.e1 FROM pm1.g1, pm1.g2", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand2_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT CONCAT(pm1.g1.e1, convert(pm1.g2.e1, string)) as x FROM pm1.g1,
pm1.g2", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand3_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT e1 FROM pm1.g1 UNION SELECT e1 FROM pm1.g2", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand4_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT COUNT(*) FROM pm1.g1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand5_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT * FROM pm1.g1 GROUP BY e1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand6_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "EXEC pm1.sq1()", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand7_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "INSERT INTO pm1.g1 (e1) VALUES ('x')", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand8_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "UPDATE pm1.g1 SET e1='x'", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand9_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "DELETE FROM pm1.g1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand10_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT COUNT(*) FROM pm1.g1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand11_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT COUNT(e1) as x FROM pm1.g1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand12_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT * FROM (EXEC pm1.sq1()) AS a", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- public void testCreateInsertCommand13_fail(){
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT 1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- // Check that e3 is not required (it has a default value)
- public void testRequiredElements1() {
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g3", //$NON-NLS-1$
- "SELECT e1, e2 FROM pm1.g3", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g3 (pm1.g3.e1, pm1.g3.e2)
VALUES (INPUTS.e1, INPUTS.e2);\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND");
//$NON-NLS-1$
- }
-
- // Check that e2 is not required (it is auto-incremented)
- public void testRequiredElements2() {
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g4", //$NON-NLS-1$
- "SELECT e1, e3 FROM pm1.g3", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g3 (pm1.g3.e1, pm1.g3.e3)
VALUES (INPUTS.e1, INPUTS.e3);\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND");
//$NON-NLS-1$
- }
-
- // Check that e1 is required (it is not-nullable, not auto-incrementable, and has no
default value)
- public void testRequiredElements3() {
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g5", //$NON-NLS-1$
- "SELECT e2, e3 FROM pm1.g3", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(),
- null);
- }
-
- // Verify that elements that are not updateable are exlcluded from update and delete
procedures
- public void testNonUpdateableElements() {
- helpTest(UpdateProcedureGenerator.UPDATE_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "select e1 as a, e2 from pm1.g1 where e4 > 5",
//$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(false),
- "CREATE PROCEDURE\nBEGIN\nUPDATE pm1.g1 SET e2 = INPUTS.e2 WHERE
TRANSLATE CRITERIA;\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
- // Verify that elements that are not updateable are exlcluded from update and delete
procedures
- public void testNonUpdateableElements2() {
- helpTest(UpdateProcedureGenerator.INSERT_PROCEDURE,
- "vm1.g1", //$NON-NLS-1$
- "SELECT e1, e2 FROM pm1.g1", //$NON-NLS-1$
- TestUpdateProcedureGenerator.example1(false),
- "CREATE PROCEDURE\nBEGIN\nINSERT INTO pm1.g1 (pm1.g1.e2) VALUES
(INPUTS.e2);\nROWS_UPDATED = VARIABLES.ROWCOUNT;\nEND"); //$NON-NLS-1$
- }
-
-}
Modified: trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -2750,9 +2750,9 @@
obj.putProperty(FakeMetadataObject.Props.IS_VIRTUAL,
model.getProperty(FakeMetadataObject.Props.IS_VIRTUAL));
obj.putProperty(FakeMetadataObject.Props.PLAN, plan);
obj.putProperty(FakeMetadataObject.Props.UPDATE, Boolean.TRUE);
- if (updatePlan != null) {
- obj.putProperty(FakeMetadataObject.Props.UPDATE_PROCEDURE, updatePlan);
- }
+ obj.putProperty(FakeMetadataObject.Props.UPDATE_PROCEDURE, updatePlan);
+ obj.putProperty(FakeMetadataObject.Props.INSERT_PROCEDURE, "");
+ obj.putProperty(FakeMetadataObject.Props.DELETE_PROCEDURE, "");
return obj;
}
Modified: trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java 2010-11-21
01:48:42 UTC (rev 2733)
+++
trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -31,6 +31,7 @@
import org.teiid.core.types.DataTypeManager;
import org.teiid.metadata.Column;
import org.teiid.metadata.ColumnSet;
+import org.teiid.metadata.ForeignKey;
import org.teiid.metadata.KeyRecord;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Procedure;
@@ -438,6 +439,17 @@
}
return key;
}
+
+ public static ForeignKey createForeignKey(String name, Table group, List<Column>
elements, KeyRecord primaryKey) {
+ ForeignKey key = new ForeignKey();
+ key.setName(name);
+ for (Column column : elements) {
+ key.addColumn(column);
+ }
+ key.setPrimaryKey(primaryKey);
+ group.getForeignKeys().add(key);
+ return key;
+ }
/**
* Create a physical model with default settings.
Added: trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
(rev 0)
+++
trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -0,0 +1,341 @@
+/*
+ * 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.validator;
+
+import static org.junit.Assert.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+import org.teiid.api.exception.query.QueryParserException;
+import org.teiid.api.exception.query.QueryResolverException;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.core.TeiidException;
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.metadata.Column;
+import org.teiid.metadata.ColumnSet;
+import org.teiid.metadata.KeyRecord;
+import org.teiid.metadata.MetadataStore;
+import org.teiid.metadata.Procedure;
+import org.teiid.metadata.Schema;
+import org.teiid.metadata.Table;
+import org.teiid.metadata.BaseColumn.NullType;
+import org.teiid.metadata.KeyRecord.Type;
+import org.teiid.query.mapping.relational.QueryNode;
+import org.teiid.query.metadata.TransformationMetadata;
+import org.teiid.query.parser.QueryParser;
+import org.teiid.query.report.ReportItem;
+import org.teiid.query.resolver.QueryResolver;
+import org.teiid.query.resolver.util.ResolverUtil;
+import org.teiid.query.sql.lang.Command;
+import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.unittest.RealMetadataFactory;
+
+@SuppressWarnings("nls")
+public class TestUpdateValidator {
+
+ private UpdateValidator helpTest(String sql, TransformationMetadata md, boolean
shouldFail) {
+ try {
+ String vGroup = "gx";
+ Command command = createView(sql, md, vGroup);
+
+ UpdateValidator uv = new UpdateValidator(md, true, true, true);
+ GroupSymbol gs = new GroupSymbol(vGroup);
+ ResolverUtil.resolveGroup(gs, md);
+ uv.validate(command, ResolverUtil.resolveElementsInGroup(gs, md));
+ boolean failed = false;
+ for (ReportItem item : (Collection<ReportItem>)uv.getReport().getItems()) {
+ if (item instanceof ValidatorFailure) {
+ failed = true;
+ if (!shouldFail) {
+ fail(item.toString());
+ }
+ }
+ }
+ if (!failed && shouldFail) {
+ fail("expeceted failures, but got none: " + uv.getReport());
+ }
+ return uv;
+ } catch (TeiidException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static Command createView(String sql, TransformationMetadata md, String vGroup)
+ throws QueryParserException, QueryResolverException,
+ TeiidComponentException {
+ QueryNode vm1g1n1 = new QueryNode(vGroup, sql);
+ Table vm1g1 = RealMetadataFactory.createUpdatableVirtualGroup(vGroup,
md.getMetadataStore().getSchema("vm1"), vm1g1n1);
+
+ Command command = QueryParser.getQueryParser().parseCommand(sql);
+ QueryResolver.resolveCommand(command, md);
+
+ List<SingleElementSymbol> symbols = command.getProjectedSymbols();
+ String[] names = new String[symbols.size()];
+ String[] types = new String[symbols.size()];
+ int i = 0;
+ for (SingleElementSymbol singleElementSymbol : symbols) {
+ names[i] = singleElementSymbol.getShortName();
+ types[i++] = DataTypeManager.getDataTypeName(singleElementSymbol.getType());
+ }
+
+ RealMetadataFactory.createElements(vm1g1, names, types);
+ return command;
+ }
+
+ public static TransformationMetadata example1() {
+ return example1(true);
+ }
+
+ public static TransformationMetadata example1(boolean allUpdatable) {
+ MetadataStore metadataStore = new MetadataStore();
+
+ // Create models
+ Schema pm1 = RealMetadataFactory.createPhysicalModel("pm1", metadataStore);
//$NON-NLS-1$
+ Schema vm1 = RealMetadataFactory.createVirtualModel("vm1", metadataStore);
//$NON-NLS-1$
+
+ // Create physical groups
+ Table pm1g1 = RealMetadataFactory.createPhysicalGroup("g1", pm1);
//$NON-NLS-1$
+ Table pm1g2 = RealMetadataFactory.createPhysicalGroup("g2", pm1);
//$NON-NLS-1$
+ Table pm1g3 = RealMetadataFactory.createPhysicalGroup("g3", pm1);
//$NON-NLS-1$
+
+ // Create physical elements
+ List<Column> pm1g1e = RealMetadataFactory.createElements(pm1g1,
+ 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 });
+ if (!allUpdatable) {
+ pm1g1e.get(0).setUpdatable(false);
+ }
+
+ KeyRecord pk = RealMetadataFactory.createKey(Type.Primary, "pk", pm1g1,
pm1g1e.subList(0, 1));
+
+ List<Column> pm1g2e = RealMetadataFactory.createElements(pm1g2,
+ 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 });
+
+ RealMetadataFactory.createKey(Type.Primary, "pk", pm1g2, pm1g1e.subList(1,
2));
+ RealMetadataFactory.createForeignKey("fk", pm1g2, pm1g2e.subList(0, 1), pk);
+
+ List<Column> pm1g3e = RealMetadataFactory.createElements(pm1g3,
+ 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 });
+ pm1g3e.get(0).setNullType(NullType.No_Nulls);
+ pm1g3e.get(0).setDefaultValue(null);
+
+ pm1g3e.get(1).setNullType(NullType.No_Nulls);
+ pm1g3e.get(1).setAutoIncremented(true);
+ pm1g3e.get(1).setDefaultValue(null);
+
+ pm1g3e.get(2).setNullType(NullType.No_Nulls);
+ pm1g3e.get(2).setDefaultValue("xyz"); //$NON-NLS-1$
+
+ // Create virtual groups
+ QueryNode vm1g1n1 = new QueryNode("g1", "SELECT e1 as a, e2 FROM pm1.g1
WHERE e3 > 5"); //$NON-NLS-1$ //$NON-NLS-2$
+ Table vm1g1 = RealMetadataFactory.createUpdatableVirtualGroup("g1", vm1,
vm1g1n1); //$NON-NLS-1$
+ QueryNode vm1g2n1 = new QueryNode("g2", "SELECT e1, e2, e3, e4 FROM
pm1.g2 WHERE e3 > 5"); //$NON-NLS-1$ //$NON-NLS-2$
+ Table vm1g2 = RealMetadataFactory.createUpdatableVirtualGroup("g2", vm1,
vm1g2n1); //$NON-NLS-1$
+ QueryNode vm1g3n1 = new QueryNode("g3", "SELECT e1, e3 FROM
pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
+ Table vm1g3 = RealMetadataFactory.createUpdatableVirtualGroup("g3",
vm1, vm1g3n1); //$NON-NLS-1$
+ QueryNode vm1g4n1 = new QueryNode("g4", "SELECT e1, e2 FROM
pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
+ Table vm1g4 = RealMetadataFactory.createUpdatableVirtualGroup("g4",
vm1, vm1g4n1); //$NON-NLS-1$
+ QueryNode vm1g5n1 = new QueryNode("g5", "SELECT e2, e3 FROM
pm1.g3"); //$NON-NLS-1$ //$NON-NLS-2$
+ Table vm1g5 = RealMetadataFactory.createVirtualGroup("g5", vm1,
vm1g5n1); //$NON-NLS-1$
+
+ // Create virtual elements
+ List<Column> vm1g1e = 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,
+ 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,
+ new String[] { "e1", "e2"}, //$NON-NLS-1$ //$NON-NLS-2$
+ new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER, });
+ List<Column> vm1g4e = 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,
+ new String[] { "e2","e3"}, //$NON-NLS-1$ //$NON-NLS-2$
+ new String[] { DataTypeManager.DefaultDataTypes.INTEGER,
DataTypeManager.DefaultDataTypes.BOOLEAN });
+
+ // Stored queries
+ ColumnSet<Procedure> rs1 =
RealMetadataFactory.createResultSet("rs1", new String[] { "e1",
"e2" }, new String[] { DataTypeManager.DefaultDataTypes.STRING,
DataTypeManager.DefaultDataTypes.INTEGER }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ QueryNode sq1n1 = new QueryNode("sq1", "CREATE VIRTUAL PROCEDURE
BEGIN SELECT e1, e2 FROM pm1.g1; END"); //$NON-NLS-1$ //$NON-NLS-2$
+ Procedure sq1 = RealMetadataFactory.createVirtualProcedure("pm1.sq1",
pm1, Collections.EMPTY_LIST, sq1n1); //$NON-NLS-1$
+ sq1.setResultSet(rs1);
+ // Create the facade from the store
+ return RealMetadataFactory.createTransformationMetadata(metadataStore,
"example");
+ }
+
+ //actual tests
+ @Test public void testCreateInsertCommand(){
+ helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateInsertCommand2(){ //put a constant in select statement
+ helpTest("select e1 as a, 5 from pm1.g1 where e4 > 5",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateInsertCommand3(){
+ helpTest("select * from pm1.g2 where e4 > 5",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateInsertCommand4(){ //test group alias
+ helpTest("select * from pm1.g2 as g_alias",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateInsertCommand5(){
+ helpTest("select e1 as a, e2 from pm1.g1 as g_alias where e4 > 5",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateUpdateCommand(){
+ helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateDeleteCommand(){
+ helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ @Test public void testCreateInsertCommand1(){
+ helpTest("SELECT pm1.g1.e1 FROM pm1.g1, pm1.g2",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand2_fail(){
+ helpTest("SELECT CONCAT(pm1.g1.e1, convert(pm1.g2.e1, string)) as x FROM
pm1.g1, pm1.g2",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand3_fail(){
+ helpTest("SELECT e1 FROM pm1.g1 UNION SELECT e1 FROM pm1.g2",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand4_fail(){
+ helpTest("SELECT COUNT(*) FROM pm1.g1",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand5_fail(){
+ helpTest("SELECT * FROM pm1.g1 GROUP BY e1",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand6_fail(){
+ helpTest("EXEC pm1.sq1()",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand7_fail(){
+ helpTest("INSERT INTO pm1.g1 (e1) VALUES ('x')",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand8_fail(){
+ helpTest("UPDATE pm1.g1 SET e1='x'",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand9_fail(){
+ helpTest("DELETE FROM pm1.g1",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand10_fail(){
+ helpTest("SELECT COUNT(*) FROM pm1.g1",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand11_fail(){
+ helpTest("SELECT COUNT(e1) as x FROM pm1.g1",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand12_fail(){
+ helpTest("SELECT * FROM (EXEC pm1.sq1()) AS a",
+ example1(), true);
+ }
+
+ @Test public void testCreateInsertCommand13_fail(){
+ helpTest("SELECT 1",
+ example1(), true);
+ }
+
+ // Check that e3 is not required (it has a default value)
+ @Test public void testRequiredElements1() {
+ helpTest("SELECT e1, e2 FROM pm1.g3",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ // Check that e2 is not required (it is auto-incremented)
+ @Test public void testRequiredElements2() {
+ helpTest("SELECT e1, e3 FROM pm1.g3",
+ example1(), false); //$NON-NLS-1$
+ }
+
+ // Check that e1 is required (it is not-nullable, not auto-incrementable, and has no
default value)
+ @Test public void testRequiredElements3() {
+ helpTest("SELECT e2, e3 FROM pm1.g3",
+ example1(), true);
+ }
+
+ // Verify that elements that are not updateable are exlcluded from update and delete
procedures
+ @Test public void testNonUpdateableElements() {
+ helpTest("select e1 as a, e2 from pm1.g1 where e4 > 5",
+ example1(false), false); //$NON-NLS-1$
+ }
+
+ // Verify that elements that are not updateable are exlcluded from update and delete
procedures
+ @Test public void testNonUpdateableElements2() {
+ helpTest("SELECT e1, e2 FROM pm1.g1",
+ example1(false), false); //$NON-NLS-1$
+ }
+
+ // Verify that elements that are not updateable are exlcluded from update and delete
procedures
+ @Test public void testSelectDistinct() {
+ helpTest("SELECT distinct e1, e2 FROM pm1.g1",
+ example1(), true); //$NON-NLS-1$
+ }
+
+ @Test public void testNonUpdatable() {
+ helpTest("SELECT e2 FROM vm1.g5",
+ example1(), true); //$NON-NLS-1$
+ }
+
+ @Test public void testAnsiJoin() {
+ helpTest("SELECT g1.e1, x.e2 FROM pm1.g2 x inner join pm1.g1 on (x.e1 =
g1.e1)",
+ example1(), false); //$NON-NLS-1$
+ }
+
+}
+
Property changes on:
trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2010-11-21
01:48:42 UTC (rev 2733)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2010-11-23
04:10:27 UTC (rev 2734)
@@ -693,25 +693,6 @@
helpValidate("UPDATE vm1.g1 SET e1=1 WHERE exists (select * from
vm1.g1)" , new String[] {"EXISTS (SELECT * FROM vm1.g1)"},
FakeMetadataFactory.example1Cached()); //$NON-NLS-1$ //$NON-NLS-2$
}
- @Test public void testUpdate3() throws Exception {
- QueryMetadataInterface metadata = exampleMetadata();
-
- Command command = QueryParser.getQueryParser().parseCommand("UPDATE
test.group SET p1=1"); //$NON-NLS-1$
-
- // Create external metadata
- GroupSymbol sqGroup = new GroupSymbol("pm1.sq5"); //$NON-NLS-1$
- ArrayList sqParams = new ArrayList();
- ElementSymbol in = new ElementSymbol("pm1.sq5.p1"); //$NON-NLS-1$
- in.setType(DataTypeManager.DefaultDataClasses.STRING);
- sqParams.add(in);
- Map externalMetadata = new HashMap();
- externalMetadata.put(sqGroup, sqParams);
-
- QueryResolver.resolveCommand(command, externalMetadata, metadata,
AnalysisRecord.createNonRecordingRecord());
-
- helpRunValidator(command, new String[] {"p1"}, metadata);
//$NON-NLS-1$
- }
-
@Test public void testUpdate4() throws Exception {
QueryMetadataInterface metadata = exampleMetadata();
@@ -1284,36 +1265,6 @@
FakeMetadataObject.Props.UPDATE_PROCEDURE);
}
- // variables cannot be used among insert elements
- @Test public void testCreateUpdateProcedure23() {
- String procedure = "CREATE PROCEDURE "; //$NON-NLS-1$
- procedure = procedure + "BEGIN\n"; //$NON-NLS-1$
- procedure = procedure + "DECLARE integer var1;\n"; //$NON-NLS-1$
- procedure = procedure + "Update pm1.g1 SET pm1.g1.e2 =1 , var1 = 2;\n";
//$NON-NLS-1$
- procedure = procedure + "ROWS_UPDATED =0;\n"; //$NON-NLS-1$
- procedure = procedure + "END\n"; //$NON-NLS-1$
-
- String userQuery = "UPDATE vm1.g3 SET x='x' where e3= 1";
//$NON-NLS-1$
-
- helpFailProcedure(procedure, userQuery,
- FakeMetadataObject.Props.UPDATE_PROCEDURE);
- }
-
- // variables cannot be used among insert elements
- @Test public void testCreateUpdateProcedure24() {
- String procedure = "CREATE PROCEDURE "; //$NON-NLS-1$
- procedure = procedure + "BEGIN\n"; //$NON-NLS-1$
- procedure = procedure + "DECLARE integer var1;\n"; //$NON-NLS-1$
- procedure = procedure + "Update pm1.g1 SET pm1.g1.e2 =1 , INPUT.x =
2;\n"; //$NON-NLS-1$
- procedure = procedure + "ROWS_UPDATED =0;\n"; //$NON-NLS-1$
- procedure = procedure + "END\n"; //$NON-NLS-1$
-
- String userQuery = "UPDATE vm1.g3 SET x='x' where e3= 1";
//$NON-NLS-1$
-
- helpFailProcedure(procedure, userQuery,
- FakeMetadataObject.Props.UPDATE_PROCEDURE);
- }
-
// virtual group elements used in procedure in if statement(TRANSLATE CRITERIA)
@Test public void testCreateUpdateProcedure25() {
String procedure = "CREATE PROCEDURE "; //$NON-NLS-1$