/* // $Id: //guest/julian_hyde/saffron/src/main/saffron/rel/plan/NestedLoopJoinPlan.java#1 $ // 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.plan; import openjava.mop.OJClass; import openjava.mop.OJField; import openjava.ptree.Expression; import openjava.ptree.util.SyntheticClass; import saffron.PlanWriter; import saffron.runtime.IteratorPlan; import saffron.runtime.Plan; import saffron.util.Util; import java.util.Iterator; /** * todo: * * @author jhyde * @since 15 February, 2002 * @version $Id: //guest/julian_hyde/saffron/src/main/saffron/rel/plan/NestedLoopJoinPlan.java#1 $ **/ class NestedLoopJoinPlan extends IteratorPlan { PlanNestedLoopJoin rel; Plan leftPlan, rightPlan; Expression conditionPlan; public NestedLoopJoinPlan( PlanNestedLoopJoin rel, Plan leftPlan, Plan rightPlan, Expression conditionPlan) { this.rel = rel; this.leftPlan = leftPlan; this.rightPlan = rightPlan; this.conditionPlan = conditionPlan; } public void explain(PlanWriter pw) { rel.explain(pw); } // implement Plan public void execute() { iterator = new NestedLoopJoinIterator(); } private class NestedLoopJoinIterator implements Iterator { boolean haveMovedToNext; boolean done; // todo: unify done & haveMovedToNext into state /** If the left input is a synthetic class, then leftFields are the n * fields within the row to put leftSourceFields, the n fields of the * row from the left input. If the left input is a real class, then * leftFields has only one member, and leftSourceFields is null. */ OJField[] leftFields, rightFields, leftSourceFields, rightSourceFields; Object row; NestedLoopJoinIterator() { try { int j = 0; OJClass leftClass = rel.getLeft().getRowType(); if (false /*rel.left.getRowWidth() == 1*/) { leftSourceFields = null; leftFields = new OJField[1]; leftFields[0] = rel.getRowType().getField( SyntheticClass.makeField(j++)); } else { leftSourceFields = leftClass.getDeclaredFields(); // Util.assert( // leftSourceFields.length == rel.left.getRowWidth()); leftFields = new OJField[leftSourceFields.length]; for (int i = 0; i < leftFields.length; i++) { leftFields[i] = rel.getRowType().getField( SyntheticClass.makeField(j++)); } } OJClass rightClass = rel.getRight().getRowType(); if (false /*rel.right.getRowWidth() == 1*/) { rightSourceFields = null; rightFields = new OJField[1]; rightFields[0] = rel.getRowType().getField( SyntheticClass.makeField(j++)); } else { rightSourceFields = rightClass.getDeclaredFields(); // Util.assert( // rightSourceFields.length == rel.right.getRowWidth()); rightFields = new OJField[rightSourceFields.length]; for (int i = 0; i < rightFields.length; i++) { rightFields[i] = rel.getRowType().getField( SyntheticClass.makeField(j++)); } } } catch (openjava.mop.NoSuchMemberException e) { throw Util.newInternal(e); } done = false; leftPlan.execute(); if (leftPlan.hasNext()) { Util.discard(leftPlan.next()); rightPlan.execute(); haveMovedToNext = false; moveToNextIfNecessary(); } else { done = true; } } private Object createRow() { try { return rel.getRowType().newInstance(); } catch (IllegalAccessException e) { throw Util.newInternal(e); } catch (InstantiationException e) { throw Util.newInternal(e); } catch (openjava.mop.CannotExecuteException e) { throw Util.newInternal(e); } } private void moveToNext() { while (true) { while (rightPlan.hasNext()) { Util.discard(rightPlan.next()); if (Util.evaluateBoolean(conditionPlan)) { try { row = createRow(); Object leftRow = leftPlan.current(); if (leftSourceFields == null) { leftFields[0].set(row, leftRow); } else { for (int i = 0; i < leftFields.length; i++) { Object v = leftSourceFields[i].get( leftRow); leftFields[i].set(row, v); } } Object rightRow = rightPlan.current(); if (rightSourceFields == null) { rightFields[0].set(row, rightRow); } else { for (int i = 0; i < rightFields.length; i++) { Object v = rightSourceFields[i].get( rightRow); rightFields[i].set(row, v); } } } catch (IllegalAccessException e) { throw Util.newInternal(e); } return; // have found matching pair } } // Have run out of rows from right. Take the next row from // the left. if (leftPlan.hasNext()) { Util.discard(leftPlan.next()); rightPlan.execute(); } else { done = true; return; } } } // This method is not thread-safe. private void moveToNextIfNecessary() { if (!haveMovedToNext) { haveMovedToNext = true; moveToNext(); } } /** * We cannot call {@link #moveToNext} from {@link #next}, because * it calls {@link #next} on the underlying iterators, and might * therefore invalidate the objects it is about to return. We * therefore call {@link #moveToNext} the first time that they call * {@link #hasNext}. After they have called {@link #hasNext}, the * row just returned may be invalid. */ public boolean hasNext() { moveToNextIfNecessary(); return !done; } /** This method does not call {@link #moveToNext}, as would be * typical. See {@link #hasNext} for more details. */ public Object next() { moveToNextIfNecessary(); haveMovedToNext = false; return row; } public void remove() { throw new UnsupportedOperationException(); } }; /** As {@link NestedLoopJoinIterator}, but does re-uses the same object * for each row, which causes problems if a consumer is blocking * ({@link Group}, for example). Not currently used. */ private class NestedLoopJoinIterator_noCopy implements Iterator { boolean haveMovedToNext; boolean done; // todo: unify done & haveMovedToNext into state OJField leftField, rightField; Object row; NestedLoopJoinIterator_noCopy() { try { leftField = rel.getRowType().getField( SyntheticClass.makeField(0)); rightField = rel.getRowType().getField( SyntheticClass.makeField(1)); } catch (openjava.mop.NoSuchMemberException e) { throw Util.newInternal(e); } try { row = rel.getRowType().newInstance(); } catch (IllegalAccessException e) { throw Util.newInternal(e); } catch (InstantiationException e) { throw Util.newInternal(e); } catch (openjava.mop.CannotExecuteException e) { throw Util.newInternal(e); } done = false; leftPlan.execute(); if (leftPlan.hasNext()) { Util.discard(leftPlan.next()); rightPlan.execute(); haveMovedToNext = false; moveToNextIfNecessary(); } else { done = true; } } private void moveToNext() { while (true) { while (rightPlan.hasNext()) { Object o = rightPlan.next(); if (Util.evaluateBoolean(conditionPlan)) { try { rightField.set(row, o); } catch (IllegalAccessException e) { throw Util.newInternal(e); } return; // have found matching pair } } // Have run out of rows from right. Take the next row from // the left. if (leftPlan.hasNext()) { Object o = leftPlan.next(); try { leftField.set(row, o); } catch (IllegalAccessException e) { throw Util.newInternal(e); } rightPlan.execute(); } else { done = true; return; } } } // This method is not thread-safe. private void moveToNextIfNecessary() { if (!haveMovedToNext) { haveMovedToNext = true; moveToNext(); } } /** * We cannot call {@link #moveToNext} from {@link #next}, because * it calls {@link #next} on the underlying iterators, and might * therefore invalidate the objects it is about to return. We * therefore call {@link #moveToNext} the first time that they call * {@link #hasNext}. After they have called {@link #hasNext}, the * row just returned may be invalid. */ public boolean hasNext() { moveToNextIfNecessary(); return !done; } /** This method does not call {@link #moveToNext}, as would be * typical. See {@link #hasNext} for more details. */ public Object next() { moveToNextIfNecessary(); haveMovedToNext = false; return row; } public void remove() { throw new UnsupportedOperationException(); } }; } // End NestedLoopJoinPlan.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 1467 | Julian Hyde |
saffron: First saffron check-in; incorporate my changes to openjava. |