diff --git a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledCursorUtils.java b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledCursorUtils.java
index 9703e573966d2..4c03731c8b788 100644
--- a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledCursorUtils.java
+++ b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledCursorUtils.java
@@ -24,11 +24,8 @@
import org.neo4j.internal.kernel.api.NodeCursor;
import org.neo4j.internal.kernel.api.PropertyCursor;
import org.neo4j.internal.kernel.api.Read;
-import org.neo4j.internal.kernel.api.RelationshipGroupCursor;
-import org.neo4j.internal.kernel.api.RelationshipTraversalCursor;
-import org.neo4j.internal.kernel.api.helpers.RelationshipDenseSelectionCursor;
import org.neo4j.internal.kernel.api.helpers.RelationshipSelectionCursor;
-import org.neo4j.internal.kernel.api.helpers.RelationshipSparseSelectionCursor;
+import org.neo4j.internal.kernel.api.helpers.RelationshipSelections;
import org.neo4j.kernel.api.StatementConstants;
import org.neo4j.kernel.api.exceptions.EntityNotFoundException;
import org.neo4j.storageengine.api.EntityType;
@@ -102,59 +99,14 @@ public static boolean nodeHasLabel( Read read, NodeCursor nodeCursor, long node,
}
public static RelationshipSelectionCursor nodeGetRelationships( Read read, CursorFactory cursors, NodeCursor node,
- long nodeId,
- Direction direction, int[] relTypes )
+ long nodeId, Direction direction, int[] types )
{
read.singleNode( nodeId, node );
if ( !node.next() )
{
return RelationshipSelectionCursor.EMPTY;
}
- if ( node.isDense() )
- {
- RelationshipGroupCursor groupCursor = cursors.allocateRelationshipGroupCursor();
- node.relationships( groupCursor );
- RelationshipTraversalCursor traversalCursor = cursors.allocateRelationshipTraversalCursor();
- RelationshipDenseSelectionCursor selectionCursor =
- new RelationshipDenseSelectionCursor();
- switch ( direction )
- {
- case OUTGOING:
- selectionCursor.outgoing( groupCursor, traversalCursor, relTypes );
- break;
- case INCOMING:
- selectionCursor.incoming( groupCursor, traversalCursor, relTypes );
- break;
- case BOTH:
- selectionCursor.all( groupCursor, traversalCursor, relTypes );
- break;
- default:
- throw new IllegalStateException( "Code style is awesome" );
- }
- return selectionCursor;
- }
- else
- {
- RelationshipTraversalCursor traversalCursor = cursors.allocateRelationshipTraversalCursor();
- node.allRelationships( traversalCursor );
- RelationshipSparseSelectionCursor selectionCursor =
- new RelationshipSparseSelectionCursor();
- switch ( direction )
- {
- case OUTGOING:
- selectionCursor.outgoing( traversalCursor, relTypes );
- break;
- case INCOMING:
- selectionCursor.incoming( traversalCursor, relTypes );
- break;
- case BOTH:
- selectionCursor.all( traversalCursor, relTypes );
- break;
- default:
- throw new IllegalStateException( "Code style is awesome" );
- }
- return selectionCursor;
- }
+ return RelationshipSelections.selectionCursor( cursors, node, direction, types );
}
public static RelationshipSelectionCursor nodeGetRelationships( Read read, CursorFactory cursors, NodeCursor node,
diff --git a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala
index 136523c56e195..6ba87e5fad12c 100644
--- a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala
+++ b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala
@@ -34,7 +34,6 @@ import org.neo4j.cypher.internal.runtime.interpreted.commands.convert.DirectionC
import org.neo4j.cypher.internal.runtime.interpreted.commands.expressions.{OnlyDirectionExpander, TypeAndDirectionExpander}
import org.neo4j.cypher.internal.util.v3_4.{EntityNotFoundException, FailedIndexException}
import org.neo4j.cypher.internal.v3_4.expressions.SemanticDirection
-import org.neo4j.cypher.internal.v3_4.expressions.SemanticDirection.{BOTH, INCOMING, OUTGOING}
import org.neo4j.cypher.internal.v3_4.logical.plans.{QualifiedName, _}
import org.neo4j.graphalgo.impl.path.ShortestPath
import org.neo4j.graphalgo.impl.path.ShortestPath.ShortestPathPredicate
@@ -42,6 +41,7 @@ import org.neo4j.graphdb._
import org.neo4j.graphdb.security.URLAccessValidationError
import org.neo4j.graphdb.traversal.{Evaluators, TraversalDescription, Uniqueness}
import org.neo4j.internal.kernel.api._
+import org.neo4j.internal.kernel.api.helpers.RelationshipSelections.selectionCursor
import org.neo4j.internal.kernel.api.helpers._
import org.neo4j.kernel.GraphDatabaseQueryService
import org.neo4j.kernel.api.exceptions.ProcedureException
@@ -172,70 +172,31 @@ final class TransactionBoundQueryContext(val transactionalContext: Transactional
else tokenWrite.labelGetOrCreateForName(labelName)
}
- private def selectRelationships(nodeCursor: NodeCursor, dir: SemanticDirection, types: Option[Array[Int]]) = {
- val cursors = transactionalContext.kernelTransaction.cursors()
+ def getRelationshipsForIds(node: Long, dir: SemanticDirection,
+ types: Option[Array[Int]]): Iterator[RelationshipValue] = {
+ val read = reads()
+ read.singleNode(node, nodeCursor)
+ if (!nodeCursor.next()) return Iterator.empty
val factory = new RelationshipFactory[RelationshipValue] {
override def relationship(id: Long, startNodeId: Long, typeId: Int,
endNodeId: Long): RelationshipValue =
fromRelationshipProxy(entityAccessor.newRelationshipProxy(id, startNodeId, typeId, endNodeId))
}
- if (nodeCursor.isDense) {
- val groupCursor = cursors.allocateRelationshipGroupCursor()
- nodeCursor.relationships(groupCursor)
- val traversalCursor = cursors.allocateRelationshipTraversalCursor()
- val denseSelectionIterator = new RelationshipDenseSelectionIterator[RelationshipValue](factory)
- dir match {
- case OUTGOING => denseSelectionIterator.outgoing(groupCursor, traversalCursor, types.orNull)
- case INCOMING => denseSelectionIterator.incoming(groupCursor, traversalCursor, types.orNull)
- case BOTH => denseSelectionIterator.all(groupCursor, traversalCursor, types.orNull)
- }
- denseSelectionIterator
- } else {
- val traversalCursor = cursors.allocateRelationshipTraversalCursor()
- nodeCursor.allRelationships(traversalCursor)
- val sparseSelectionIterator = new RelationshipSparseSelectionIterator[RelationshipValue](factory)
- dir match {
- case OUTGOING => sparseSelectionIterator.outgoing(traversalCursor, types.orNull)
- case INCOMING => sparseSelectionIterator.incoming(traversalCursor, types.orNull)
- case BOTH => sparseSelectionIterator.all(traversalCursor, types.orNull)
- }
- sparseSelectionIterator
- }
- }
- private def selectRelationshipsPrimitive(nodeCursor: NodeCursor, dir: SemanticDirection, types: Option[Array[Int]]) = {
- val cursors = transactionalContext.kernelTransaction.cursors()
- if (nodeCursor.isDense) {
- val groupCursor = cursors.allocateRelationshipGroupCursor()
- nodeCursor.relationships(groupCursor)
- val traversalCursor = cursors.allocateRelationshipTraversalCursor()
- val denseSelectionCursor = new RelationshipDenseSelectionCursor()
- dir match {
- case OUTGOING => denseSelectionCursor.outgoing(groupCursor, traversalCursor, types.orNull)
- case INCOMING => denseSelectionCursor.incoming(groupCursor, traversalCursor, types.orNull)
- case BOTH => denseSelectionCursor.all(groupCursor, traversalCursor, types.orNull)
- }
- denseSelectionCursor
- } else {
- val traversalCursor = cursors.allocateRelationshipTraversalCursor()
- nodeCursor.allRelationships(traversalCursor)
- val sparseSelectionCursor = new RelationshipSparseSelectionCursor()
- dir match {
- case OUTGOING => sparseSelectionCursor.outgoing(traversalCursor, types.orNull)
- case INCOMING => sparseSelectionCursor.incoming(traversalCursor, types.orNull)
- case BOTH => sparseSelectionCursor.all(traversalCursor, types.orNull)
- }
- sparseSelectionCursor
- }
- }
+ val cursor = selectionCursor(transactionalContext.kernelTransaction.cursors(), nodeCursor,
+ toGraphDb(dir), types.orNull)
+ new CursorIterator[RelationshipValue] {
- def getRelationshipsForIds(node: Long, dir: SemanticDirection,
- types: Option[Array[Int]]): Iterator[RelationshipValue] = {
- val read = reads()
- read.singleNode(node, nodeCursor)
- if (!nodeCursor.next()) return Iterator.empty
+ override protected def close(): Unit = cursor.close()
- selectRelationships(nodeCursor, dir, types).asScala
+ override protected def fetchNext(): RelationshipValue =
+ if (cursor.next())
+ fromRelationshipProxy(entityAccessor.newRelationshipProxy(cursor.relationshipReference(),
+ cursor.sourceNodeReference(),
+ cursor.`type`(),
+ cursor.targetNodeReference()))
+ else null
+ }
}
override def getRelationshipsForIdsPrimitive(node: Long, dir: SemanticDirection,
@@ -243,7 +204,8 @@ final class TransactionBoundQueryContext(val transactionalContext: Transactional
val read = reads()
read.singleNode(node, nodeCursor)
if (!nodeCursor.next()) RelationshipIterator.EMPTY
- else new RelationshipCursorIterator(selectRelationshipsPrimitive(nodeCursor, dir, types))
+ else new RelationshipCursorIterator(
+ selectionCursor(transactionalContext.kernelTransaction.cursors(), nodeCursor, toGraphDb(dir), types.orNull))
}
override def getRelationshipFor(relationshipId: Long, typeId: Int, startNodeId: Long,
diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/helpers/RelationshipSelections.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/helpers/RelationshipSelections.java
new file mode 100644
index 0000000000000..0f36980668b57
--- /dev/null
+++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/helpers/RelationshipSelections.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.kernel.api.helpers;
+
+import org.neo4j.graphdb.Direction;
+import org.neo4j.graphdb.ResourceIterator;
+import org.neo4j.internal.kernel.api.CursorFactory;
+import org.neo4j.internal.kernel.api.NodeCursor;
+import org.neo4j.internal.kernel.api.RelationshipGroupCursor;
+import org.neo4j.internal.kernel.api.RelationshipTraversalCursor;
+
+/**
+ * Utilities for dealing with RelationshipSelectionCursor and corresponding iterators.
+ */
+public final class RelationshipSelections
+{
+ private RelationshipSelections()
+ {
+ throw new UnsupportedOperationException( "Do not instantiate" );
+ }
+
+ /**
+ * Returns a selection cursor given the provided node cursor, direction and relationship types.
+ *
+ * @param cursors A cursor factor used for allocating the needed cursors
+ * @param node A node cursor positioned at the current node.
+ * @param direction The direction of the the relationship.
+ * @param types The types of the relationship
+ * @return A cursor that allows traversing the relationship chain.
+ */
+ public static RelationshipSelectionCursor selectionCursor( CursorFactory cursors, NodeCursor node,
+ Direction direction, int[] types )
+ {
+ if ( node.isDense() )
+ {
+ RelationshipDenseSelectionCursor selectionCursor = new RelationshipDenseSelectionCursor();
+ setupDense( selectionCursor, cursors, node, direction, types );
+ return selectionCursor;
+ }
+ else
+ {
+ RelationshipSparseSelectionCursor selectionCursor = new RelationshipSparseSelectionCursor();
+
+ setupSparse( selectionCursor, cursors, node, direction, types );
+ return selectionCursor;
+ }
+ }
+
+ /**
+ * Returns a resource iterator given the provided node cursor, direction and relationship types.
+ *
+ * @param cursors A cursor factor used for allocating the needed cursors
+ * @param node A node cursor positioned at the current node.
+ * @param direction The direction of the the relationship.
+ * @param types The types of the relationship
+ * @param factory factory for creating instance of generic type T
+ * @return An iterator that allows traversing the relationship chain.
+ */
+ public static ResourceIterator selectionIterator( CursorFactory cursors, NodeCursor node,
+ Direction direction, int[] types, RelationshipFactory factory )
+ {
+ if ( node.isDense() )
+ {
+ RelationshipDenseSelectionIterator selectionIterator =
+ new RelationshipDenseSelectionIterator<>( factory );
+ setupDense( selectionIterator, cursors, node, direction, types );
+ return selectionIterator;
+ }
+ else
+ {
+ RelationshipSparseSelectionIterator selectionIterator =
+ new RelationshipSparseSelectionIterator<>( factory );
+
+ setupSparse( selectionIterator, cursors, node, direction, types );
+ return selectionIterator;
+ }
+ }
+
+ private static void setupDense( RelationshipDenseSelection denseSelection, CursorFactory cursors, NodeCursor node,
+ Direction direction, int[] types )
+ {
+
+ RelationshipGroupCursor groupCursor = cursors.allocateRelationshipGroupCursor();
+ RelationshipTraversalCursor traversalCursor = cursors.allocateRelationshipTraversalCursor();
+ try
+ {
+ node.relationships( groupCursor );
+ switch ( direction )
+ {
+ case OUTGOING:
+ denseSelection.outgoing( groupCursor, traversalCursor, types );
+ break;
+ case INCOMING:
+ denseSelection.incoming( groupCursor, traversalCursor, types );
+ break;
+ case BOTH:
+ denseSelection.all( groupCursor, traversalCursor, types );
+ break;
+ default:
+ throw new IllegalStateException( "Unknown direction: " + direction );
+ }
+ }
+ catch ( Throwable t )
+ {
+ groupCursor.close();
+ traversalCursor.close();
+ throw t;
+ }
+ }
+
+ private static void setupSparse( RelationshipSparseSelection sparseSelection,
+ CursorFactory cursors, NodeCursor node, Direction direction, int[] types )
+ {
+ RelationshipTraversalCursor traversalCursor = cursors.allocateRelationshipTraversalCursor();
+ try
+ {
+ node.allRelationships( traversalCursor );
+ switch ( direction )
+ {
+ case OUTGOING:
+ sparseSelection.outgoing( traversalCursor, types );
+ break;
+ case INCOMING:
+ sparseSelection.incoming( traversalCursor, types );
+ break;
+ case BOTH:
+ sparseSelection.all( traversalCursor, types );
+ break;
+ default:
+ throw new IllegalStateException( "Unknown direction: " + direction );
+ }
+ }
+ catch ( Throwable t )
+ {
+ traversalCursor.close();
+ throw t;
+ }
+ }
+}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java
index 947c8069ab99c..427d9b13f85df 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java
@@ -42,10 +42,6 @@
import org.neo4j.internal.kernel.api.LabelSet;
import org.neo4j.internal.kernel.api.NodeCursor;
import org.neo4j.internal.kernel.api.PropertyCursor;
-import org.neo4j.internal.kernel.api.helpers.RelationshipDenseSelectionIterator;
-import org.neo4j.internal.kernel.api.RelationshipGroupCursor;
-import org.neo4j.internal.kernel.api.helpers.RelationshipSparseSelectionIterator;
-import org.neo4j.internal.kernel.api.RelationshipTraversalCursor;
import org.neo4j.internal.kernel.api.TokenRead;
import org.neo4j.internal.kernel.api.exceptions.InvalidTransactionTypeKernelException;
import org.neo4j.internal.kernel.api.exceptions.KernelException;
@@ -71,6 +67,7 @@
import static org.neo4j.collection.primitive.PrimitiveIntCollections.map;
import static org.neo4j.graphdb.Label.label;
import static org.neo4j.helpers.collection.Iterators.asList;
+import static org.neo4j.internal.kernel.api.helpers.RelationshipSelections.selectionIterator;
import static org.neo4j.kernel.api.StatementConstants.NO_SUCH_LABEL;
import static org.neo4j.kernel.api.StatementConstants.NO_SUCH_RELATIONSHIP_TYPE;
import static org.neo4j.kernel.impl.core.TokenHolder.NO_ID;
@@ -762,77 +759,7 @@ private ResourceIterator getRelationshipSelectionIterator( Directi
throw new NotFoundException( format( "Node %d not found", nodeId ) );
}
- if ( node.isDense() )
- {
- RelationshipTraversalCursor relationship = transaction.cursors().allocateRelationshipTraversalCursor();
- RelationshipGroupCursor relationshipGroup = transaction.cursors().allocateRelationshipGroupCursor();
- try
- {
- node.relationships( relationshipGroup );
- RelationshipDenseSelectionIterator denseCursor =
- new RelationshipDenseSelectionIterator<>( spi::newRelationshipProxy );
-
- switch ( direction )
- {
- case OUTGOING:
- denseCursor.outgoing( relationshipGroup, relationship, typeIds );
- break;
-
- case INCOMING:
- denseCursor.incoming( relationshipGroup, relationship, typeIds );
- break;
-
- case BOTH:
- denseCursor.all( relationshipGroup, relationship, typeIds );
- break;
-
- default:
- throw new IllegalStateException( "Unsupported direction: " + direction );
- }
-
- return denseCursor;
- }
- catch ( Throwable e )
- {
- relationshipGroup.close();
- throw e;
- }
- }
- else
- {
- RelationshipTraversalCursor relationship = transaction.cursors().allocateRelationshipTraversalCursor();
- try
- {
- node.allRelationships( relationship );
- RelationshipSparseSelectionIterator sparseCursor =
- new RelationshipSparseSelectionIterator<>( spi::newRelationshipProxy );
-
- switch ( direction )
- {
- case OUTGOING:
- sparseCursor.outgoing( relationship, typeIds );
- break;
-
- case INCOMING:
- sparseCursor.incoming( relationship, typeIds );
- break;
-
- case BOTH:
- sparseCursor.all( relationship, typeIds );
- break;
-
- default:
- throw new IllegalStateException( "Unsupported direction: " + direction );
- }
-
- return sparseCursor;
- }
- catch ( Throwable e )
- {
- relationship.close();
- throw e;
- }
- }
+ return selectionIterator( transaction.cursors(), node, direction, typeIds, spi::newRelationshipProxy );
}
private int[] relTypeIds( RelationshipType[] types, Statement statement )