[teiid-commits] teiid SVN: r2743 - in trunk: engine/src/main/java/org/teiid/query/optimizer/relational/rules and 4 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Nov 24 13:11:43 EST 2010


Author: shawkins
Date: 2010-11-24 13:11:42 -0500 (Wed, 24 Nov 2010)
New Revision: 2743

Modified:
   trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.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/validator/UpdateValidator.java
   trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
Log:
TEIID-1349 adding support to detect key preserved in non-ansi joins

Modified: trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml	2010-11-24 17:42:05 UTC (rev 2742)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/updatable_views.xml	2010-11-24 18:11:42 UTC (rev 2743)
@@ -50,7 +50,7 @@
 		
 		<para>A key-preserved table has a primary or unique key that would remain unique if it were projected into the result of the query.  
 		Note that it is not actually required for a view to reference the key columns in the SELECT clause.  
-		The query engine can detect a key preserved table by analyzing the join structure - which is currently required to be in ANSI join form.  
+		The query engine can detect a key preserved table by analyzing the join structure.  
 		The engine will ensure that a join of a key-preserved table must be against one of its foreign keys.</para>		
 	</section>
 	

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-24 17:42:05 UTC (rev 2742)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java	2010-11-24 18:11:42 UTC (rev 2743)
@@ -540,7 +540,7 @@
 			return true;
 		}
 		HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
-		ResolverUtil.findKeyPreserinvg((FromClause)query.getFrom().getClauses().get(0), keyPreservingGroups, metadata);
+		ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
 		return NewCalculateCostUtil.usesKey(expressions, keyPreservingGroups, metadata);			
 	}
 

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-24 17:42:05 UTC (rev 2742)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java	2010-11-24 18:11:42 UTC (rev 2743)
@@ -56,6 +56,7 @@
 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.CompareCriteria;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.FromClause;
 import org.teiid.query.sql.lang.JoinPredicate;
@@ -941,8 +942,67 @@
 	    symbol.setOutputName(name);
 	}
 	
-	public static void findKeyPreserinvg(FromClause clause, Set<GroupSymbol> keyPreservingGroups, QueryMetadataInterface metadata)
+	public static void findKeyPreserved(Query query, Set<GroupSymbol> keyPreservingGroups, QueryMetadataInterface metadata)
 	throws TeiidComponentException, QueryMetadataException {
+		if (query.getFrom() == null) {
+			return;
+		}
+		if (query.getFrom().getClauses().size() == 1) {
+			findKeyPreserved((FromClause)query.getFrom().getClauses().get(0), keyPreservingGroups, metadata);
+			return;
+		}
+		//non-ansi join
+		Set<GroupSymbol> groups = new HashSet<GroupSymbol>(query.getFrom().getGroups());
+		for (GroupSymbol groupSymbol : groups) {
+			if (metadata.getUniqueKeysInGroup(groupSymbol.getMetadataID()).isEmpty()) {
+				return;
+			}
+		}
+		LinkedList<Expression> leftExpressions = new LinkedList<Expression>();
+		LinkedList<Expression> rightExpressions = new LinkedList<Expression>();
+		for (Criteria crit : Criteria.separateCriteriaByAnd(query.getCriteria())) {
+			if (!(crit instanceof CompareCriteria)) {
+				continue;
+			}
+			CompareCriteria cc = (CompareCriteria)crit;
+			if (cc.getOperator() != CompareCriteria.EQ) {
+				continue;
+			}
+			if (cc.getLeftExpression() instanceof ElementSymbol && cc.getRightExpression() instanceof ElementSymbol) {
+				ElementSymbol left = (ElementSymbol)cc.getLeftExpression();
+				ElementSymbol right = (ElementSymbol)cc.getRightExpression();
+				int compare = left.getGroupSymbol().compareTo(right.getGroupSymbol());
+				if (compare > 0) {
+					leftExpressions.add(left);
+					rightExpressions.add(right);
+				} else if (compare != 0) {
+					leftExpressions.add(right);
+					rightExpressions.add(left);
+				}
+			}
+		}
+		HashMap<List<GroupSymbol>, List<HashSet<Object>>> crits = createGroupMap(leftExpressions, rightExpressions);
+		HashSet<GroupSymbol> tempSet = new HashSet<GroupSymbol>();
+		for (GroupSymbol group : groups) {
+			LinkedHashSet<GroupSymbol> visited = new LinkedHashSet<GroupSymbol>();
+			LinkedList<GroupSymbol> toVisit = new LinkedList<GroupSymbol>();
+			toVisit.add(group);
+			while (!toVisit.isEmpty()) {
+				GroupSymbol visiting = toVisit.removeLast();
+				if (!visited.add(visiting)) {
+					continue;
+				}
+				toVisit.addAll(findKeyPreserved(tempSet, Collections.singleton(visiting), crits, true, metadata, groups));
+				toVisit.addAll(findKeyPreserved(tempSet, Collections.singleton(visiting), crits, false, metadata, groups));
+			}
+			if (visited.containsAll(groups)) {
+				keyPreservingGroups.add(group);
+			}
+		}
+	}
+		
+	public static void findKeyPreserved(FromClause clause, Set<GroupSymbol> keyPreservingGroups, QueryMetadataInterface metadata)
+	throws TeiidComponentException, QueryMetadataException {
 		if (clause instanceof UnaryFromClause) {
 			UnaryFromClause ufc = (UnaryFromClause)clause;
 		    
@@ -956,9 +1016,9 @@
 				return;
 			}
 			HashSet<GroupSymbol> leftPk = new HashSet<GroupSymbol>();
-			findKeyPreserinvg(jp.getLeftClause(), leftPk, metadata);
+			findKeyPreserved(jp.getLeftClause(), leftPk, metadata);
 			HashSet<GroupSymbol> rightPk = new HashSet<GroupSymbol>();
-			findKeyPreserinvg(jp.getRightClause(), rightPk, metadata);
+			findKeyPreserved(jp.getRightClause(), rightPk, metadata);
 			
 			if (leftPk.isEmpty() && rightPk.isEmpty()) {
 				return;
@@ -973,48 +1033,58 @@
 			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());
-			}
+			HashMap<List<GroupSymbol>, List<HashSet<Object>>> crits = createGroupMap(leftExpressions, rightExpressions);
 			if (!leftPk.isEmpty() && (jp.getJoinType() == JoinType.JOIN_INNER || jp.getJoinType() == JoinType.JOIN_LEFT_OUTER)) {
-				findKeyPreserving(keyPreservingGroups, leftPk, crits, true, metadata);
+				findKeyPreserved(keyPreservingGroups, leftPk, crits, true, metadata, rightPk);
 			} 
 			if (!rightPk.isEmpty() && (jp.getJoinType() == JoinType.JOIN_INNER || jp.getJoinType() == JoinType.JOIN_RIGHT_OUTER)) {
-				findKeyPreserving(keyPreservingGroups, rightPk, crits, false, metadata);
+				findKeyPreserved(keyPreservingGroups, rightPk, crits, false, metadata, leftPk);
 			}
 		}
 	}
 
-	static private void findKeyPreserving(Set<GroupSymbol> keyPreservingGroups,
-		HashSet<GroupSymbol> pk,
-		HashMap<List<GroupSymbol>, List<HashSet<Object>>> crits, boolean left, QueryMetadataInterface metadata)
+	private static HashMap<List<GroupSymbol>, List<HashSet<Object>>> createGroupMap(
+			LinkedList<Expression> leftExpressions,
+			LinkedList<Expression> rightExpressions) {
+		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());
+		}
+		return crits;
+	}
+
+	static private HashSet<GroupSymbol> findKeyPreserved(Set<GroupSymbol> keyPreservingGroups,
+		Set<GroupSymbol> pk,
+		HashMap<List<GroupSymbol>, List<HashSet<Object>>> crits, boolean left, QueryMetadataInterface metadata, Set<GroupSymbol> otherGroups)
 		throws TeiidComponentException, QueryMetadataException {
+		HashSet<GroupSymbol> result = new HashSet<GroupSymbol>();
 		for (GroupSymbol gs : pk) {
 			for (Map.Entry<List<GroupSymbol>, List<HashSet<Object>>> entry : crits.entrySet()) {
-				if (!entry.getKey().get(left?0:1).equals(gs)) {
+				if (!entry.getKey().get(left?0:1).equals(gs) || !otherGroups.contains(entry.getKey().get(left?1:0))) {
 					continue;
 				}
 				if (RuleRaiseAccess.matchesForeignKey(metadata, entry.getValue().get(left?0:1), entry.getValue().get(left?1:0), gs, false)) {
 					keyPreservingGroups.add(gs);
+					result.add(entry.getKey().get(left?1:0));
 				}
 			}
 		}
+		return result;
 	}
     
 }

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-24 17:42:05 UTC (rev 2742)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2010-11-24 18:11:42 UTC (rev 2743)
@@ -688,7 +688,7 @@
 			if (query.getFrom().getClauses().size() > 1) {
 				continue;
 			}
-			ResolverUtil.findKeyPreserinvg((FromClause)query.getFrom().getClauses().get(0), keyPreservingGroups, metadata);
+			ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
 			if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata)) {
 				continue;
 			}

Modified: trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java	2010-11-24 17:42:05 UTC (rev 2742)
+++ trunk/engine/src/main/java/org/teiid/query/validator/UpdateValidator.java	2010-11-24 18:11:42 UTC (rev 2743)
@@ -35,7 +35,6 @@
 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;
@@ -233,9 +232,7 @@
     	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);
-    	}
+		ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
     	
 		for (GroupSymbol groupSymbol : keyPreservingGroups) {
 			setUpdateFlags(groupSymbol);

Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java	2010-11-24 17:42:05 UTC (rev 2742)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestUpdateValidator.java	2010-11-24 18:11:42 UTC (rev 2743)
@@ -230,6 +230,11 @@
         helpTest("SELECT pm1.g1.e1 FROM pm1.g1, pm1.g2",
             example1(), true);
     }
+    
+    @Test public void testCreateInsertCommand14(){
+        helpTest("SELECT pm1.g2.e1 FROM pm1.g1, pm1.g2 where g1.e1 = g2.e1",
+            example1(), false);
+    }
 
     @Test public void testCreateInsertCommand2_fail(){
         helpTest("SELECT CONCAT(pm1.g1.e1, convert(pm1.g2.e1, string)) as x FROM pm1.g1, pm1.g2",



More information about the teiid-commits mailing list