/* // $Id: //guest/julian_hyde/saffron/src/main/saffron/rel/SubqueryFinder.java#3 $ // Saffron preprocessor and data engine // Copyright (C) 2002 Julian Hyde <julian.hyde@mail.com> // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 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 // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // See the COPYING file located in the top-level-directory of // the archive of this library for complete text of license. */ package saffron.rel; import openjava.mop.OJClass; import openjava.mop.Toolbox; import openjava.ptree.*; import openjava.ptree.util.GenericVisitor; import openjava.tools.DebugOut; import saffron.util.RelEnvironment; class SubqueryFinder extends GenericVisitor { QueryInfo queryInfo; SubqueryFinder(QueryInfo queryInfo) { this.queryInfo = queryInfo; } public void visit(BinaryExpression p) throws ParseTreeException { if (p.getOperator() == BinaryExpression.IN) { Expression left = p.getLeft(), right = p.getRight(); DebugOut.println( "SubqueryFinder: found IN: left=[" + left + "], right=[" + right + "]"); Rel oldFrom = queryInfo.getRoot(); left = queryInfo.convertExpToInternal(left); Rel rightRel = queryInfo.convertFromExpToRel(right); OJClass rightRowType = Toolbox.getRowType(queryInfo.env, right); boolean wrap = rightRowType.isPrimitive(); if (wrap) { rightRel = new Project( queryInfo.cluster, rightRel, new Expression[] { Toolbox.box( rightRowType, RelEnvironment.makeReference(0))}, new String[] {null}, Project.flagNone); } int leafCount = queryInfo.countLeaves(oldFrom); // Variable with which to refer to the new relation Variable v = RelEnvironment.makeReference(leafCount); // Join the sub-query from the 'in' to the tree built up from // the 'from' clause Join join = new Join( queryInfo.cluster, oldFrom, new Distinct(queryInfo.cluster, rightRel), new BinaryExpression( left, BinaryExpression.EQUAL, Toolbox.castObject( v, rightRowType.primitiveWrapper(), rightRowType)), Join.LEFT); queryInfo.setRoot(join); // Replace the 'in' condition with 'q != null' BinaryExpression condition = new BinaryExpression( RelEnvironment.makeReference(0), BinaryExpression.NOTEQUAL, Literal.constantNull()); p.replace(condition); // signal that we want to stop iteration (not really an error) throw new Toolbox.StopIterationException(); } else { super.visit(p); } } /** * Replaces an <code>exists</code> expression. For example,<blockquote> * * <pre>select from dept * where dept.state.equals("CA") && <b>exists ( * select from emp where emp.deptno == dept.deptno)</b></pre> * * </blockquote>becomes<blockquote> * * <pre>select from dept <b>left join ( * select distinct true from ( * select from emp where emp.deptno == dept.deptno)) as test</b> * where dept.state.equals("CA") && <b>test</b></pre> * * </blockquote> */ public void visit(UnaryExpression p) throws ParseTreeException { if (p.getOperator() == UnaryExpression.EXISTS) { Expression right = p.getExpression(); DebugOut.println( "SubqueryFinder: found EXISTS: expr=[" + right + "]"); Rel oldFrom = queryInfo.getRoot(); Rel rightRel = queryInfo.convertFromExpToRel(right); Rel rightProject = new Project( queryInfo.cluster, rightRel, new Expression[] {Literal.constantTrue()}, null, Project.flagNone); Rel rightDistinct = new Distinct( queryInfo.cluster, rightProject); queryInfo.leaves.add(rightDistinct); Join join = new Join( queryInfo.cluster, oldFrom, rightDistinct, Literal.constantTrue(), Join.LEFT); queryInfo.setRoot(join); // Replace the 'exists' with a reference to the single, boolean // field from the new relation (which will be false if there is no // row coming from the other side of the outer join). // int leafCount = queryInfo.countLeaves(oldFrom); int leafCount = queryInfo.countColumns(oldFrom); Expression condition = RelEnvironment.makeFieldAccess( 0, leafCount); // Expression condition = new Variable(RelEnvironment.makeName(leafCount)); p.replace(condition); // signal that we want to stop iteration (not really an error) throw new Toolbox.StopIterationException(); } else { super.visit(p); } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#5 | 1853 | Julian Hyde |
saffron: Further improve binding of rows to variables. |
||
#4 | 1818 | Julian Hyde |
saffron: Oops (forgot ParseTreeAction.java), Correlation now works, Smarter code generation (now burrow into synthetic classes, rather than invoking constructors). |
||
#3 | 1801 | Julian Hyde |
saffron: add ObjectSchema; rules can now be matched more than once; started to implement correlations in queries in from list. |
||
#2 | 1748 | Julian Hyde |
saffron: convert unit tests to JUnit; add CallingConvention.ITERABLE; lots of other stuff; release 0.1. |
||
#1 | 1467 | Julian Hyde |
saffron: First saffron check-in; incorporate my changes to openjava. |