[teiid-commits] teiid SVN: r3603 - in trunk: documentation/reference/src/main/docbook/en-US/content and 10 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Nov 2 15:48:52 EDT 2011


Author: shawkins
Date: 2011-11-02 15:48:52 -0400 (Wed, 02 Nov 2011)
New Revision: 3603

Modified:
   trunk/build/kits/jboss-container/teiid-releasenotes.html
   trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java
   trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/Limit.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestLimit.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
Log:
TEIID-1806 ensuring consistent handling of unordered limits

Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html	2011-11-02 19:48:52 UTC (rev 3603)
@@ -37,6 +37,7 @@
   <LI><B>Native Queries</B> - added the ability to specify native query SQL for JDBC physical tables and stored procedures via extension metadata.
   <LI><B>View removal hint</B> - the NO_UNNEST hint now also applies to from clause views and subqueries.  It will instruct the planner to not perform view flattening.
   <LI><B>Non-blocking statement execution</B> - Teiid JDBC extensions TeiidStatement and TeiidPreparedStatement can be used to submit queries against embedded connections with a callback to process results in a non-blocking manner.
+  <LI><B>NON_STRICT limit hint</B> - the NON_STRICT hint can be used with unordered limits to tell the optimizer to not inhibit push operations even if the results will not be consistent with the logical application of the limit.
 </UL>
 
 <h2><a name="Compatibility">Compatibility Issues</a></h2>
@@ -51,6 +52,7 @@
   <li>Leave was added as a reserved word.
   <li>Lob inlining is incompatible with clients older than 7.6.  If a 7.6 server will have older clients that use lobs connect to it, then the BufferService property inlineLobs should be set to false in the teiid-jboss-beans.xml file.
   <li>Oracle translators assume they are using Oracle supplied drivers.  If that is not the case, set the Oracle translator execution property oracleSuppliedDriver to false.
+  <li>Unordered limits are handled strictly by default.  They are longer pushed through conditions, dup removal, or UNION not all - and cannot have conditions pushed through them.  Use the NON_STRICT hint to change the behavior to Teiid 7.1 handling.
 </ul>
 
 <h4>from 7.4</h4>

Modified: trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml	2011-11-02 19:48:52 UTC (rev 3603)
@@ -438,6 +438,11 @@
           <para>The terms FIRST/NEXT are interchangable as well as ROW/ROWS.
           </para>
         </listitem>
+        <listitem>
+          <para>The limit clause may take an optional preceeding NON_STRICT hint to indicate that push operations should not be inhibited even if the results will not be consistent with the logical application of the limit.
+          The hint is only needed on unordered limits, e.g. "SELECT * FROM VW /*+ NON_STRICT */ LIMIT 2".
+          </para>
+        </listitem>
       </itemizedlist>
       <itemizedlist>
         <para>Examples:

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	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -1151,6 +1151,9 @@
         	if (limit.isImplicit()) {
         		limitNode.setProperty(Info.IS_IMPLICIT_LIMIT, true);
         	}
+        	if (limit.isStrict()) {
+        		limitNode.setProperty(Info.IS_STRICT, true);
+        	}
             attachLast(limitNode, plan);
             plan = limitNode;
         }

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -148,6 +148,7 @@
         MAX_TUPLE_LIMIT,     // Expression that evaluates to the max number of tuples generated
         OFFSET_TUPLE_COUNT,  // Expression that evaluates to the tuple offset of the starting tuple
         IS_IMPLICIT_LIMIT,   // Boolean if the limit is created by the rewriter as part of a subquery optimization
+        IS_STRICT,			 // Boolean if the unordered limit should be enforced strictly
 
         // Common AP Information
         ACCESS_PATTERNS,     // Collection <List <Object element ID> >

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -547,8 +547,8 @@
         return null;
     }
     
-    public static boolean isOrderedLimit(PlanNode node) {
-    	return node.getType() == NodeConstants.Types.TUPLE_LIMIT && NodeEditor.findNodePreOrder(node, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT | NodeConstants.Types.SET_OP) != null;
+    public static boolean isOrderedOrStrictLimit(PlanNode node) {
+    	return node.getType() == NodeConstants.Types.TUPLE_LIMIT && (NodeEditor.findNodePreOrder(node, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT | NodeConstants.Types.SET_OP) != null || node.hasProperty(Info.IS_STRICT));
     }
 
 }

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -45,6 +45,7 @@
 import org.teiid.query.optimizer.relational.plantree.NodeEditor;
 import org.teiid.query.optimizer.relational.plantree.NodeFactory;
 import org.teiid.query.optimizer.relational.plantree.PlanNode;
+import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
 import org.teiid.query.sql.lang.CompareCriteria;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.SetQuery;
@@ -135,7 +136,9 @@
 				Expression childOffset = (Expression)child.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
 				
 				combineLimits(limitNode, metadata, parentLimit, parentOffset, childLimit, childOffset);
-                
+                if (child.hasBooleanProperty(Info.IS_STRICT)) {
+                	limitNode.setProperty(Info.IS_STRICT, true);
+                }
                 NodeEditor.removeChildNode(limitNode, child);
                 limitNodes.remove(child);
                 
@@ -143,10 +146,12 @@
             }
             case NodeConstants.Types.SET_OP:
             {
-                if (!SetQuery.Operation.UNION.equals(child.getProperty(NodeConstants.Info.SET_OPERATION)) 
-                		|| !child.hasBooleanProperty(NodeConstants.Info.USE_ALL)) {
-                    return false;
-                }                                
+                if (!SetQuery.Operation.UNION.equals(child.getProperty(NodeConstants.Info.SET_OPERATION))) {
+                	return false;
+                }   
+                if (!child.hasBooleanProperty(NodeConstants.Info.USE_ALL) && limitNode.hasBooleanProperty(Info.IS_STRICT)) {
+                	return false;
+                }
                 //distribute the limit
                 List<PlanNode> grandChildren = new LinkedList<PlanNode>(child.getChildren());
                 for (PlanNode grandChild : grandChildren) {
@@ -171,13 +176,16 @@
             {
                 GroupSymbol virtualGroup = child.getGroups().iterator().next();
                 if (virtualGroup.isProcedure()) {
-                        return false;
+                    return false;
                 }
                 if (FrameUtil.isProcedure(child.getFirstChild())) {
                     return false;
                 }
                 return true;
             }
+            case NodeConstants.Types.SELECT:
+            case NodeConstants.Types.DUP_REMOVE:
+            	return !limitNode.hasBooleanProperty(Info.IS_STRICT);
             default:
             {
                 return false;

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -343,7 +343,7 @@
                 }  
             
                 satisfyAccessPatterns(critNode, currentNode);
-            } else if (FrameUtil.isOrderedLimit(currentNode)) {
+            } else if (FrameUtil.isOrderedOrStrictLimit(currentNode)) {
                 return currentNode;
             }
 		}
@@ -355,7 +355,7 @@
 		throws QueryPlannerException {
         
         //ensure that the criteria can be pushed further
-        if (sourceNode.getChildCount() == 1 && FrameUtil.isOrderedLimit(sourceNode.getFirstChild())) {
+        if (sourceNode.getChildCount() == 1 && FrameUtil.isOrderedOrStrictLimit(sourceNode.getFirstChild())) {
             return false;
         }
         

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	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -423,7 +423,7 @@
         
         //don't push criteria into an invalid location above an ordered limit - shouldn't happen 
         PlanNode limitNode = NodeEditor.findNodePreOrder(accessNode, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.SOURCE);
-        if (limitNode != null && FrameUtil.isOrderedLimit(limitNode)) {
+        if (limitNode != null && FrameUtil.isOrderedOrStrictLimit(limitNode)) {
         	return false;
         }
         

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -44,7 +44,6 @@
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.JoinType;
 import org.teiid.query.sql.symbol.AggregateSymbol;
-import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.sql.visitor.GroupsUsedByElementsVisitor;
 import org.teiid.query.util.CommandContext;
@@ -205,10 +204,6 @@
 		return NodeEditor.findAllNodes(optionalNode, NodeConstants.Types.JOIN);
     }
     
-    /**
-     * Ensure that the needed elements come only from the left hand side and 
-     * that cardinality won't matter
-     */
     static boolean useNonDistinctRows(PlanNode parent) {
 		while (parent != null) {
 			if (parent.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL)) {
@@ -229,16 +224,11 @@
 					return AggregateSymbol.areAggregatesCardinalityDependent(aggs);
 				}
 				case NodeConstants.Types.TUPLE_LIMIT: {
-					if (!(parent.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT) instanceof Constant) 
-							|| parent.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT) != null) {
+					if (FrameUtil.isOrderedOrStrictLimit(parent)) {
 						return true;
 					}
-					Constant constant = (Constant)parent.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
-					if (!Integer.valueOf(1).equals(constant.getValue())) {
-						return true;
-					}
 				}
-				//we assmue that projects of non-deterministic expressions do not matter
+				//we assume that projects of non-deterministic expressions do not matter
 			}
 			parent = parent.getParent();
 		}

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -200,7 +200,7 @@
             if (rsInfo.exceptionOnRowlimit()) {
                 limit++;
             }
-            rsQuery.setLimit(new Limit(null, new Constant(new Integer(limit))));
+            rsQuery.setLimit(new Limit(null, new Constant(limit)));
         }
         
         // this query is not eligible for staging; proceed normally.

Modified: trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -36,6 +36,7 @@
 import org.teiid.query.sql.lang.CacheHint;
 import org.teiid.query.sql.lang.FromClause;
 import org.teiid.query.sql.lang.JoinType;
+import org.teiid.query.sql.lang.Limit;
 import org.teiid.query.sql.lang.Option;
 import org.teiid.query.sql.lang.QueryCommand;
 import org.teiid.query.sql.lang.SetQuery;
@@ -213,6 +214,16 @@
         return hint;
 	}
 	
+	boolean isNonStrictHint(Token t) {
+		String[] parts = getComment(t).split("\\s"); //$NON-NLS-1$
+    	for (int i = 0; i < parts.length; i++) {
+    		if (parts[i].equalsIgnoreCase(Limit.NON_STRICT)) {
+    			return true;
+    		}
+    	}
+    	return false;
+	}
+	
 	private static Pattern CACHE_HINT = Pattern.compile("/\\*\\+?\\s*cache(\\(\\s*(pref_mem)?\\s*(ttl:\\d{1,19})?\\s*(updatable)?\\s*(scope:(session|vdb|user))?[^\\)]*\\))?[^\\*]*\\*\\/.*", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); //$NON-NLS-1$
     
 	static CacheHint getQueryCacheOption(String query) {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Limit.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Limit.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Limit.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -32,10 +32,13 @@
 
 
 public class Limit implements LanguageObject {
+	
+	public static String NON_STRICT = "NON_STRICT"; //$NON-NLS-1$
     
     private Expression offset;
     private Expression rowLimit;
     private boolean implicit;
+    private boolean strict = true;
     
     public Limit(Expression offset, Expression rowLimit) {
         this.offset = offset;
@@ -46,6 +49,14 @@
     	
     }
     
+    public void setStrict(boolean strict) {
+		this.strict = strict;
+	}
+    
+    public boolean isStrict() {
+		return strict;
+	}
+    
     public boolean isImplicit() {
 		return implicit;
 	}
@@ -96,6 +107,7 @@
     public Limit clone() {
         Limit clone = new Limit();
         clone.implicit = this.implicit;
+        clone.strict = this.strict;
         if (this.rowLimit != null) {
         	clone.setRowLimit((Expression) this.rowLimit.clone());
         }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -1777,6 +1777,14 @@
     }
 
     public void visit( Limit obj ) {
+    	if (!obj.isStrict()) {
+    		append(BEGIN_HINT);
+    		append(SPACE);
+    		append(Limit.NON_STRICT);
+    		append(SPACE);
+    		append(END_HINT);
+    		append(SPACE);
+    	}
     	if (obj.getRowLimit() == null) {
     		append(OFFSET);
     		append(SPACE);

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2011-11-02 19:48:52 UTC (rev 3603)
@@ -3164,8 +3164,10 @@
 {
 	Expression limit = null;
 	Expression offset = null;
+	Token t = null;
 }
 {
+    {t = getToken(1);}
     ((<LIMIT> offset = intParam(info)
 	[<COMMA> limit = intParam(info)])
 	{
@@ -3180,7 +3182,9 @@
     |
     (limit = fetchLimit(info)))
 	{
-		return new Limit(offset, limit);
+		Limit result = new Limit(offset, limit);
+		result.setStrict(!isNonStrictHint(t));
+		return result;
 	}
 }
 

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestLimit.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestLimit.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestLimit.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -709,7 +709,7 @@
         // pm3 model supports order by
         capFinder.addCapabilities("pm3", caps); //$NON-NLS-1$
 
-        String sql = "SELECT * FROM (SELECT * FROM pm3.g1 limit 100) as v1 where v1.e1 = 1";//$NON-NLS-1$
+        String sql = "SELECT * FROM (SELECT * FROM pm3.g1 /*+ non_strict */ limit 100) as v1 where v1.e1 = 1";//$NON-NLS-1$
         String[] expectedSql = new String[] {
             "SELECT pm3.g1.e1, pm3.g1.e2, pm3.g1.e3, pm3.g1.e4 FROM pm3.g1 WHERE pm3.g1.e1 = '1' LIMIT 100" //$NON-NLS-1$
             };
@@ -852,7 +852,7 @@
      * Note here that the criteria made it to the having clause 
      */
     @Test public void testAggregateCriteriaOverUnSortedLimit() {
-        String sql = "select a from (SELECT MAX(e2) as a FROM pm1.g1 GROUP BY e2 LIMIT 1) x where a = 0"; //$NON-NLS-1$
+        String sql = "select a from (SELECT MAX(e2) as a FROM pm1.g1 GROUP BY e2 /*+ non_strict */ LIMIT 1) x where a = 0"; //$NON-NLS-1$
         FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
         BasicSourceCapabilities caps = new BasicSourceCapabilities();
         caps.setCapabilitySupport(Capability.CRITERIA_COMPARE_EQ, true);

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java	2011-11-02 16:50:24 UTC (rev 3602)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java	2011-11-02 19:48:52 UTC (rev 3603)
@@ -1162,4 +1162,15 @@
         assertEquals("SELECT a FROM /*+ NO_UNNEST */ (SELECT a FROM db.g WHERE a2 = 5) AS x", QueryParser.getQueryParser().parseCommand(sql, new ParseInfo()).toString());         //$NON-NLS-1$
     }
     
+    @Test public void testNonStrictLimit() throws QueryParserException {
+        String sql = "SELECT a FROM x /*+ non_strict */ limit 1"; //$NON-NLS-1$
+        assertEquals("SELECT a FROM x /*+ NON_STRICT */ LIMIT 1", QueryParser.getQueryParser().parseCommand(sql, new ParseInfo()).toString());         //$NON-NLS-1$
+        
+        sql = "SELECT a FROM x /*+ non_strict */ offset 1 row"; //$NON-NLS-1$
+        assertEquals("SELECT a FROM x /*+ NON_STRICT */ OFFSET 1 ROWS", QueryParser.getQueryParser().parseCommand(sql, new ParseInfo()).toString());         //$NON-NLS-1$
+
+        sql = "SELECT a FROM x /*+ non_strict */ fetch first 1 rows only"; //$NON-NLS-1$
+        assertEquals("SELECT a FROM x /*+ NON_STRICT */ LIMIT 1", QueryParser.getQueryParser().parseCommand(sql, new ParseInfo()).toString());         //$NON-NLS-1$
+    }
+    
 }



More information about the teiid-commits mailing list