/* * ModeShape (http://www.modeshape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.modeshape.jcr.query.engine.process; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import org.junit.Before; import org.junit.Test; import org.modeshape.jcr.ExecutionContext; import org.modeshape.jcr.query.AbstractNodeSequenceTest; import org.modeshape.jcr.query.BufferManager; import org.modeshape.jcr.query.NodeSequence.RowAccessor; import org.modeshape.jcr.query.RowExtractors; import org.modeshape.jcr.query.RowExtractors.ExtractFromRow; import org.modeshape.jcr.query.engine.process.JoinSequence.RangeProducer; import org.modeshape.jcr.query.model.JoinType; import org.modeshape.jcr.query.model.TypeSystem; import org.modeshape.jcr.value.ValueTypeSystem; /** * @author Randall Hauch (rhauch@redhat.com) */ public class HashJoinSequenceTest extends AbstractNodeSequenceTest { private ExecutionContext context; private BufferManager bufferMgr; private TypeSystem types; @Override @Before public void beforeEach() { super.beforeEach(); this.context = new ExecutionContext(); this.bufferMgr = new BufferManager(context); this.types = new ValueTypeSystem(context.getValueFactories()); } @Test public void shouldInnerJoinParentToChildOnHeap() { // print(true); boolean useHeap = true; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.INNER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, leftInnerJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldInnerJoinParentToChildOffHeap() { // print(true); boolean useHeap = false; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.INNER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, leftInnerJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldLeftOuterJoinParentToChildOnHeap() { // print(true); boolean useHeap = true; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.LEFT_OUTER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, leftOuterJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldLeftOuterJoinParentToChildOffHeap() { // print(true); boolean useHeap = false; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.LEFT_OUTER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, leftOuterJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldRightOuterJoinParentToChildOnHeap() { // print(true); boolean useHeap = true; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.RIGHT_OUTER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, rightOuterJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldRightOuterJoinParentToChildOffHeap() { // print(true); boolean useHeap = false; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.RIGHT_OUTER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, rightOuterJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldFullOuterJoinParentToChildOnHeap() { // print(true); boolean useHeap = true; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.FULL_OUTER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, fullOuterJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldFullOuterJoinParentToChildOffHeap() { // print(true); boolean useHeap = false; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); print("Parent of nodes:", allNodes(), RowExtractors.extractParentNodeKey(0, cache, types)); } JoinType joinType = JoinType.FULL_OUTER; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractParentNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, fullOuterJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractParentPath(1, cache, types))); } @Test public void shouldCrossJoinParentToChildOnHeap() { // print(true); boolean useHeap = true; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); } long nodeCount = countRows(allNodes()); JoinType joinType = JoinType.CROSS; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, crossJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractPath(1, cache, types), nodeCount * nodeCount)); } @Test public void shouldCrossJoinParentToChildOffHeap() { // print(true); boolean useHeap = false; boolean pack = false; if (print()) { print("All nodes:", allNodes(), RowExtractors.extractPath(0, cache, types)); print("NodeKeys of nodes:", allNodes(), RowExtractors.extractNodeKey(0, cache, types)); } long nodeCount = countRows(allNodes()); JoinType joinType = JoinType.CROSS; ExtractFromRow leftExtractor = RowExtractors.extractNodeKey(0, cache, types); ExtractFromRow rightExtractor = RowExtractors.extractNodeKey(0, cache, types); RangeProducer<?> rangeProducer = null; HashJoinSequence join = new HashJoinSequence(workspaceName(), allNodes(), allNodes(), leftExtractor, rightExtractor, joinType, bufferMgr, cache, rangeProducer, pack, useHeap); // Verify the join ... assertRowsSatisfy(join, crossJoinVerifier(RowExtractors.extractPath(0, cache, types), RowExtractors.extractPath(1, cache, types), nodeCount * nodeCount)); } protected Verifier leftInnerJoinVerifier( final ExtractFromRow leftExtractor, final ExtractFromRow rightExtractor ) { return new Verifier() { @SuppressWarnings( "synthetic-access" ) @Override public void verify( RowAccessor currentRow ) { Object leftValue = leftExtractor.getValueInRow(currentRow); Object rightValue = rightExtractor.getValueInRow(currentRow); print("Found [" + leftValue + ", " + rightValue + "] " + rowAsString(currentRow)); assertThat(leftValue, is(rightValue)); } @Override public void complete() { } }; } protected Verifier leftOuterJoinVerifier( final ExtractFromRow leftExtractor, final ExtractFromRow rightExtractor ) { return new Verifier() { @SuppressWarnings( "synthetic-access" ) @Override public void verify( RowAccessor currentRow ) { Object leftValue = leftExtractor.getValueInRow(currentRow); Object rightValue = rightExtractor.getValueInRow(currentRow); print("Found [" + leftValue + ", " + rightValue + "] " + rowAsString(currentRow)); if (rightValue == null) return; // LEFT OUTER JOIN assertThat(leftValue, is(rightValue)); } @Override public void complete() { } }; } protected Verifier rightOuterJoinVerifier( final ExtractFromRow leftExtractor, final ExtractFromRow rightExtractor ) { return new Verifier() { @SuppressWarnings( "synthetic-access" ) @Override public void verify( RowAccessor currentRow ) { Object leftValue = leftExtractor.getValueInRow(currentRow); Object rightValue = rightExtractor.getValueInRow(currentRow); print("Found [" + leftValue + ", " + rightValue + "] " + rowAsString(currentRow)); if (leftValue == null) return; // RIGHT OUTER JOIN assertThat(leftValue, is(rightValue)); } @Override public void complete() { } }; } protected Verifier fullOuterJoinVerifier( final ExtractFromRow leftExtractor, final ExtractFromRow rightExtractor ) { return new Verifier() { @SuppressWarnings( "synthetic-access" ) @Override public void verify( RowAccessor currentRow ) { Object leftValue = leftExtractor.getValueInRow(currentRow); Object rightValue = rightExtractor.getValueInRow(currentRow); print("Found [" + leftValue + ", " + rightValue + "] " + rowAsString(currentRow)); if (leftValue == null || rightValue == null) return; // FULL OUTER JOIN assertThat(leftValue, is(rightValue)); } @Override public void complete() { } }; } protected Verifier crossJoinVerifier( final ExtractFromRow leftExtractor, final ExtractFromRow rightExtractor, final long rowCount ) { return new Verifier() { private long found = 0; @SuppressWarnings( "synthetic-access" ) @Override public void verify( RowAccessor currentRow ) { Object leftValue = leftExtractor.getValueInRow(currentRow); Object rightValue = rightExtractor.getValueInRow(currentRow); print("Found [" + leftValue + ", " + rightValue + "] " + rowAsString(currentRow)); ++found; } @Override public void complete() { assertThat(found, is(rowCount)); } }; } }