diff --git a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/ContextCreator.scala b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/ContextCreator.scala index cc68bc7243cd6..b29e6bec99739 100644 --- a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/ContextCreator.scala +++ b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/ContextCreator.scala @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2017 "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.cypher.internal.compiler.v3_2 import java.time.Clock @@ -8,29 +27,38 @@ import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilerContext import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.{Metrics, MetricsFactory, QueryGraphSolver} import org.neo4j.cypher.internal.compiler.v3_2.spi.PlanContext import org.neo4j.cypher.internal.frontend.v3_2.InputPosition -import org.neo4j.cypher.internal.frontend.v3_2.phases.{CompilationPhaseTracer, InternalNotificationLogger, Monitors} +import org.neo4j.cypher.internal.frontend.v3_2.phases.{BaseContext, CompilationPhaseTracer, InternalNotificationLogger, Monitors} -trait ContextCreator { +trait ContextCreator[Context <: BaseContext] { def create(tracer: CompilationPhaseTracer, notificationLogger: InternalNotificationLogger, planContext: PlanContext, queryText: String, - offset: Option[InputPosition]): CompilerContext + offset: Option[InputPosition], + monitors: Monitors, + createFingerprintReference: Option[PlanFingerprint] => PlanFingerprintReference, + typeConverter: RuntimeTypeConverter, + metricsFactory: MetricsFactory, + queryGraphSolver: QueryGraphSolver, + config: CypherCompilerConfiguration, + updateStrategy: UpdateStrategy, + clock: Clock): Context } -class CommunityContextCreator(monitors: Monitors, - createFingerprintReference: Option[PlanFingerprint] => PlanFingerprintReference, - typeConverter: RuntimeTypeConverter, - metricsFactory: MetricsFactory, - queryGraphSolver: QueryGraphSolver, - config: CypherCompilerConfiguration, - updateStrategy: UpdateStrategy, - clock: Clock) extends ContextCreator { +object CommunityContextCreator extends ContextCreator[CompilerContext] { override def create(tracer: CompilationPhaseTracer, notificationLogger: InternalNotificationLogger, planContext: PlanContext, queryText: String, - offset: Option[InputPosition]): CompilerContext = { + offset: Option[InputPosition], + monitors: Monitors, + createFingerprintReference: Option[PlanFingerprint] => PlanFingerprintReference, + typeConverter: RuntimeTypeConverter, + metricsFactory: MetricsFactory, + queryGraphSolver: QueryGraphSolver, + config: CypherCompilerConfiguration, + updateStrategy: UpdateStrategy, + clock: Clock): CompilerContext = { val exceptionCreator = new SyntaxExceptionCreator(queryText, offset) val metrics: Metrics = if (planContext == null) @@ -41,5 +69,4 @@ class CommunityContextCreator(monitors: Monitors, new CompilerContext(exceptionCreator, tracer, notificationLogger, planContext, typeConverter, createFingerprintReference, monitors, metrics, queryGraphSolver, config, updateStrategy, clock) } - } diff --git a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompiler.scala b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompiler.scala index 9f361f94a1100..02cbdfae45149 100644 --- a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompiler.scala +++ b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompiler.scala @@ -36,7 +36,7 @@ import org.neo4j.cypher.internal.frontend.v3_2.helpers.rewriting.RewriterStepSeq import org.neo4j.cypher.internal.frontend.v3_2.phases.{CompilationPhaseTracer, InternalNotificationLogger, Monitors} import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilerContext -case class CypherCompiler(createExecutionPlan: Transformer[CompilerContext], +case class CypherCompiler[Context <: CompilerContext](createExecutionPlan: Transformer[Context], astRewriter: ASTRewriter, cacheAccessor: CacheAccessor[Statement, ExecutionPlan], planCacheFactory: () => LFUCache[Statement, ExecutionPlan], @@ -50,7 +50,7 @@ case class CypherCompiler(createExecutionPlan: Transformer[CompilerContext], config: CypherCompilerConfiguration, updateStrategy: UpdateStrategy, clock: Clock, - contextCreation: ContextCreator) { + contextCreation: ContextCreator[Context]) { def planQuery(queryText: String, context: PlanContext, @@ -66,7 +66,9 @@ case class CypherCompiler(createExecutionPlan: Transformer[CompilerContext], planContext: PlanContext, offset: Option[InputPosition] = None, tracer: CompilationPhaseTracer): (ExecutionPlan, Map[String, Any]) = { - val context = contextCreation.create(tracer, notificationLogger, planContext, input.queryText, input.startPosition) + val context: Context = contextCreation.create(tracer, notificationLogger, planContext, input.queryText, + input.startPosition, monitors, createFingerprintReference, typeConverter, metricsFactory, + queryGraphSolver, config, updateStrategy, clock) val preparedCompilationState = prepareForCaching.transform(input, context) val cache = provideCache(cacheAccessor, cacheMonitor, planContext) val isStale = (plan: ExecutionPlan) => plan.isStale(planContext.txIdProvider, planContext.statistics) @@ -86,28 +88,29 @@ case class CypherCompiler(createExecutionPlan: Transformer[CompilerContext], val plannerName = PlannerName(plannerNameText) val startState = CompilationState(queryText, offset, plannerName) //TODO: these nulls are a short cut - val context = contextCreation.create(tracer, notificationLogger, planContext = null, rawQueryText, offset) + val context = contextCreation.create(tracer, notificationLogger, planContext = null, rawQueryText, offset, monitors, + createFingerprintReference, typeConverter, metricsFactory, queryGraphSolver, config, updateStrategy, clock) CompilationPhases.parsing(sequencer).transform(startState, context) } - val irConstruction: Transformer[CompilerContext] = + val irConstruction: Transformer[Context] = ResolveTokens andThen CreatePlannerQuery.adds[UnionQuery] andThen OptionalMatchRemover - val prepareForCaching: Transformer[CompilerContext] = + val prepareForCaching: Transformer[Context] = RewriteProcedureCalls andThen ProcedureDeprecationWarnings andThen ProcedureWarnings - val costBasedPlanning: Transformer[CompilerContext] = + val costBasedPlanning: Transformer[Context] = QueryPlanner().adds[LogicalPlan] andThen PlanRewriter(sequencer) andThen If(_.unionQuery.readOnly) ( CheckForUnresolvedTokens ) - val planAndCreateExecPlan: Transformer[CompilerContext] = + val planAndCreateExecPlan: Transformer[Context] = ProcedureCallOrSchemaCommandPlanBuilder andThen If(_.maybeExecutionPlan.isEmpty)( CompilationPhases.lateAstRewriting andThen diff --git a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerFactory.scala b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerFactory.scala index 7fd02569e940b..e6831fe70db51 100644 --- a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerFactory.scala +++ b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerFactory.scala @@ -23,14 +23,14 @@ import java.time.Clock import org.neo4j.cypher.internal.compiler.v3_2.executionplan._ import org.neo4j.cypher.internal.compiler.v3_2.helpers.RuntimeTypeConverter -import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilerContext import org.neo4j.cypher.internal.compiler.v3_2.planner.logical._ +import org.neo4j.cypher.internal.compiler.v3_2.phases.{CompilerContext, Transformer} import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.idp._ import org.neo4j.cypher.internal.frontend.v3_2.ast.Statement import org.neo4j.cypher.internal.frontend.v3_2.helpers.rewriting.RewriterStepSequencer import org.neo4j.cypher.internal.frontend.v3_2.phases.Monitors -object CypherCompilerFactory { +class CypherCompilerFactory[C <: CompilerContext, T <: Transformer[C]] { val monitorTag = "cypher3.2" def costBasedCompiler(config: CypherCompilerConfiguration, @@ -41,7 +41,8 @@ object CypherCompilerFactory { runtimeName: Option[RuntimeName], updateStrategy: Option[UpdateStrategy], typeConverter: RuntimeTypeConverter, - runtimeBuilder: RuntimeBuilder[CompilerContext]): CypherCompiler = { + runtimeBuilder: RuntimeBuilder[T], + contextCreator: ContextCreator[C]): CypherCompiler[C] = { val rewriter = new ASTRewriter(rewriterSequencer) val metricsFactory = CachedMetricsFactory(SimpleMetricsFactory) @@ -60,9 +61,6 @@ object CypherCompilerFactory { val cacheMonitor = monitors.newMonitor[AstCacheMonitor](monitorTag) val cache = new MonitoringCacheAccessor[Statement, ExecutionPlan](cacheMonitor) - val contextCreator = new CommunityContextCreator(monitors, createFingerprintReference, typeConverter, - metricsFactory, queryGraphSolver, config, actualUpdateStrategy, clock) - CypherCompiler(runtimePipeline, rewriter, cache, planCacheFactory, cacheMonitor, monitors, rewriterSequencer, createFingerprintReference, typeConverter, metricsFactory, queryGraphSolver, config, actualUpdateStrategy, clock, contextCreator) diff --git a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/RuntimeBuilder.scala b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/RuntimeBuilder.scala index c9bc17a1c003f..e143fdca76014 100644 --- a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/RuntimeBuilder.scala +++ b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/RuntimeBuilder.scala @@ -22,12 +22,13 @@ package org.neo4j.cypher.internal.compiler.v3_2 import org.neo4j.cypher.internal.compiler.v3_2.phases._ import org.neo4j.cypher.internal.frontend.v3_2.InvalidArgumentException -trait RuntimeBuilder[C <: CompilerContext] { - def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): Transformer[C] +trait RuntimeBuilder[T <: Transformer[_]] { + def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): T } -object CommunityRuntimeBuilder extends RuntimeBuilder[CompilerContext] { - def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): Transformer[CompilerContext] = runtimeName match { +object CommunityRuntimeBuilder extends RuntimeBuilder[Transformer[CompilerContext]] { + override def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): Transformer[CompilerContext] = + runtimeName match { case None | Some(InterpretedRuntimeName) => BuildInterpretedExecutionPlan diff --git a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/planDescription/renderAsTreeTable.scala b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/planDescription/renderAsTreeTable.scala index 19cbbcce83093..5ef1dfe91accb 100644 --- a/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/planDescription/renderAsTreeTable.scala +++ b/community/cypher/cypher-compiler-3.2/src/main/scala/org/neo4j/cypher/internal/compiler/v3_2/planDescription/renderAsTreeTable.scala @@ -21,7 +21,6 @@ package org.neo4j.cypher.internal.compiler.v3_2.planDescription import org.neo4j.cypher.internal.compiler.v3_2.planDescription.InternalPlanDescription.Arguments._ -import scala.Predef import scala.collection.{Map, mutable} object renderAsTreeTable extends (InternalPlanDescription => String) { @@ -35,7 +34,7 @@ object renderAsTreeTable extends (InternalPlanDescription => String) { val MAX_VARIABLE_COLUMN_WIDTH = 100 private val OTHER = "Other" private val HEADERS = Seq(OPERATOR, ESTIMATED_ROWS, ROWS, HITS, TIME, VARIABLES, OTHER) - val newLine = System.lineSeparator() + private val newLine = System.lineSeparator() def apply(plan: InternalPlanDescription): String = { @@ -43,8 +42,8 @@ object renderAsTreeTable extends (InternalPlanDescription => String) { val lines = accumulate(plan) def compactLine(line: Line, previous: Seq[(Line, CompactedLine)]) = { - val repeatedVariables = if (previous.size > 0) previous.head._1.variables.intersect(line.variables) else Set.empty[String] - new CompactedLine(line, repeatedVariables) + val repeatedVariables = if (previous.nonEmpty) previous.head._1.variables.intersect(line.variables) else Set.empty[String] + CompactedLine(line, repeatedVariables) } val compactedLines = lines.reverse.foldLeft(Seq.empty[(Line, CompactedLine)]) { (acc, line) => @@ -63,7 +62,7 @@ object renderAsTreeTable extends (InternalPlanDescription => String) { val result = new StringBuilder((2 + newLine.length + headers.map(width).sum) * (lines.size * 2 + 3)) def pad(width:Int, char:String=" ") = - for (i <- 1 to width) result.append(char) + for (_ <- 1 to width) result.append(char) def divider(line:LineDetails = null) = { for (header <- headers) { if (line != null && header == OPERATOR && line.connection.isDefined) { @@ -188,14 +187,14 @@ case class CompactedLine(line: Line, repeated: Set[String]) extends LineDetails val varSep = ", " val typeSep = " -- " val suffix = ", ..." - val formattedVariables = formatVariables(renderAsTreeTable.MAX_VARIABLE_COLUMN_WIDTH) + val formattedVariables: String = formatVariables(renderAsTreeTable.MAX_VARIABLE_COLUMN_WIDTH) def apply(key: String): Justified = if (key == renderAsTreeTable.VARIABLES) Left(formattedVariables) else line(key) - def connection = line.connection + def connection: Option[String] = line.connection private def formattedVars(vars: List[String], prefix: String = "") = vars match { case v :: Nil => List(prefix + v) @@ -203,10 +202,10 @@ case class CompactedLine(line: Line, repeated: Set[String]) extends LineDetails case _ => vars } - def formatVariables(length: Int) = { + def formatVariables(length: Int): String = { val newVars = (line.variables -- repeated).toList.sorted.map(PlanDescriptionArgumentSerializer.removeGeneratedNames) val oldVars = repeated.toList.sorted.map(PlanDescriptionArgumentSerializer.removeGeneratedNames) - val all = if(newVars.length > 0) + val all = if(newVars.nonEmpty) formattedVars(newVars) ++ formattedVars(oldVars, typeSep) else formattedVars(oldVars) @@ -239,7 +238,7 @@ case class CompactedLine(line: Line, repeated: Set[String]) extends LineDetails } sealed abstract class Justified(text:String) { - def length = text.length + def length: Int = text.length } case class Left(text:String) extends Justified(text) case class Right(text:String) extends Justified(text) diff --git a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/CommunityCypherEngineProvider.java b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/CommunityCypherEngineProvider.java index a00d25d000144..5248247d653b8 100644 --- a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/CommunityCypherEngineProvider.java +++ b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/CommunityCypherEngineProvider.java @@ -59,7 +59,7 @@ protected QueryExecutionEngine createEngine( Dependencies deps, GraphDatabaseAPI LogProvider logProvider = logService.getInternalLogProvider(); CommunityCompatibilityFactory compatibilityFactory = new CommunityCompatibilityFactory( queryService, kernelAPI, monitors, logProvider ); - + deps.satisfyDependencies( compatibilityFactory ); return new ExecutionEngine( queryService, logProvider, compatibilityFactory); } } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CompatibilityCache.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CompatibilityCache.scala index cfdbde20f7853..b9a87dcc4e694 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CompatibilityCache.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CompatibilityCache.scala @@ -22,7 +22,7 @@ package org.neo4j.cypher.internal import org.neo4j.cypher.internal.compatibility.v2_3.helpers._ import org.neo4j.cypher.internal.compatibility.v3_1.helpers._ import org.neo4j.cypher.internal.compatibility.{v2_3, v3_1, _} -import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration +import org.neo4j.cypher.internal.compiler.v3_2.{CommunityContextCreator, CommunityRuntimeBuilder, CypherCompilerConfiguration} import org.neo4j.cypher.internal.frontend.v3_2.InvalidArgumentException import org.neo4j.cypher.{CypherCodeGenMode, CypherPlanner, CypherRuntime, CypherUpdateStrategy} import org.neo4j.helpers.Clock @@ -43,7 +43,7 @@ trait CompatibilityFactory { def create(spec: PlannerSpec_v3_1, config: CypherCompilerConfiguration): v3_1.Compatibility - def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility + def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility[_] } class CommunityCompatibilityFactory(graph: GraphDatabaseQueryService, kernelAPI: KernelAPI, kernelMonitors: KernelMonitors, @@ -65,21 +65,22 @@ class CommunityCompatibilityFactory(graph: GraphDatabaseQueryService, kernelAPI: v3_1.CostCompatibility(graph, as3_1(config), CompilerEngineDelegator.CLOCK, kernelMonitors, kernelAPI, log, spec.planner, spec.runtime, spec.updateStrategy) } - override def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility = + override def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility[_] = (spec.planner, spec.runtime) match { case (CypherPlanner.rule, _) => throw new InvalidArgumentException("The rule planner is no longer a valid planner option in Neo4j 3.2. If you need to use it, please compatibility mode Cypher 3.1") case (_, CypherRuntime.compiled) => throw new InvalidArgumentException("The compiled runtime is only available in the Enterprise version of Neo4j") case _ => - v3_2.CostCompatibility(config, CompilerEngineDelegator.CLOCK, kernelMonitors, kernelAPI, log, spec.planner, spec.runtime, spec.codeGenMode, spec.updateStrategy) + v3_2.CostCompatibility(config, CompilerEngineDelegator.CLOCK, kernelMonitors, kernelAPI, log, + spec.planner, spec.runtime, spec.updateStrategy, CommunityRuntimeBuilder, CommunityContextCreator) } } class CompatibilityCache(factory: CompatibilityFactory) extends CompatibilityFactory { private val cache_v2_3 = new mutable.HashMap[PlannerSpec_v2_3, v2_3.Compatibility] private val cache_v3_1 = new mutable.HashMap[PlannerSpec_v3_1, v3_1.Compatibility] - private val cache_v3_2 = new mutable.HashMap[PlannerSpec_v3_2, v3_2.Compatibility] + private val cache_v3_2 = new mutable.HashMap[PlannerSpec_v3_2, v3_2.Compatibility[_]] override def create(spec: PlannerSpec_v2_3, config: CypherCompilerConfiguration): v2_3.Compatibility = cache_v2_3.getOrElseUpdate(spec, factory.create(spec, config)) @@ -87,6 +88,6 @@ class CompatibilityCache(factory: CompatibilityFactory) extends CompatibilityFac override def create(spec: PlannerSpec_v3_1, config: CypherCompilerConfiguration): v3_1.Compatibility = cache_v3_1.getOrElseUpdate(spec, factory.create(spec, config)) - override def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility = + override def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility[_] = cache_v3_2.getOrElseUpdate(spec, factory.create(spec, config)) } diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/Compatibility.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/Compatibility.scala index 473c3285fa0ed..1ebe2695a0531 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/Compatibility.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/Compatibility.scala @@ -23,7 +23,7 @@ import org.neo4j.cypher.internal._ import org.neo4j.cypher.internal.compatibility._ import org.neo4j.cypher.internal.compiler.v3_2 import org.neo4j.cypher.internal.compiler.v3_2.executionplan.{LegacyNodeIndexUsage, LegacyRelationshipIndexUsage, SchemaIndexScanUsage, SchemaIndexSeekUsage, ExecutionPlan => ExecutionPlan_v3_2} -import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilationState +import org.neo4j.cypher.internal.compiler.v3_2.phases.{CompilationState, CompilerContext} import org.neo4j.cypher.internal.compiler.v3_2.{InfoLogger, ExplainMode => ExplainModev3_2, NormalMode => NormalModev3_2, ProfileMode => ProfileModev3_2} import org.neo4j.cypher.internal.frontend.v3_2.helpers.rewriting.RewriterStepSequencer import org.neo4j.cypher.internal.frontend.v3_2.phases.{CompilationPhaseTracer, RecordingNotificationLogger} @@ -38,7 +38,7 @@ import org.neo4j.logging.Log import scala.util.Try -trait Compatibility { +trait Compatibility[C <: CompilerContext] { val queryCacheSize: Int val kernelMonitors: KernelMonitors val kernelAPI: KernelAPI @@ -50,7 +50,7 @@ trait Compatibility { if (assertionsEnabled()) newValidating else newPlain } - protected val compiler: v3_2.CypherCompiler + protected val compiler: v3_2.CypherCompiler[C] implicit val executionMonitor: QueryExecutionMonitor = kernelMonitors.newMonitor(classOf[QueryExecutionMonitor]) diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/CostCompatibility.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/CostCompatibility.scala index d4d797bd107ce..3a6b342850998 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/CostCompatibility.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_2/CostCompatibility.scala @@ -21,24 +21,26 @@ package org.neo4j.cypher.internal.compatibility.v3_2 import java.time.Clock -import org.neo4j.cypher.internal.compiler.v3_1.codegen.{ByteCodeMode, SourceCodeMode} import org.neo4j.cypher.internal.compiler.v3_2._ -import org.neo4j.cypher.{CypherCodeGenMode, CypherPlanner, CypherRuntime, CypherUpdateStrategy} +import org.neo4j.cypher.internal.compiler.v3_2.phases.{CompilerContext, Transformer} +import org.neo4j.cypher.{CypherPlanner, CypherRuntime, CypherUpdateStrategy} import org.neo4j.kernel.api.KernelAPI import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} import org.neo4j.logging.Log -case class CostCompatibility(config: CypherCompilerConfiguration, +case class CostCompatibility[C <: CompilerContext, T <: Transformer[C]](config: CypherCompilerConfiguration, clock: Clock, kernelMonitors: KernelMonitors, kernelAPI: KernelAPI, log: Log, planner: CypherPlanner, runtime: CypherRuntime, - codeGenMode: CypherCodeGenMode, - updateStrategy: CypherUpdateStrategy) extends Compatibility { + updateStrategy: CypherUpdateStrategy, + runtimeBuilder: RuntimeBuilder[T], + contextCreator: ContextCreator[C]) extends Compatibility[C] { + assert(contextCreator != null) - protected override val compiler: CypherCompiler = { + protected override val compiler: CypherCompiler[C] = { val maybePlannerName = planner match { case CypherPlanner.default => None case CypherPlanner.cost | CypherPlanner.idp => Some(IDPPlannerName) @@ -52,12 +54,6 @@ case class CostCompatibility(config: CypherCompilerConfiguration, case CypherRuntime.compiled => Some(CompiledRuntimeName) } - val maybeCodeGenMode = codeGenMode match { - case CypherCodeGenMode.default => None - case CypherCodeGenMode.byteCode => Some(ByteCodeMode) - case CypherCodeGenMode.sourceCode => Some(SourceCodeMode) - } - val maybeUpdateStrategy = updateStrategy match { case CypherUpdateStrategy.eager => Some(eagerUpdateStrategy) case _ => None @@ -65,8 +61,9 @@ case class CostCompatibility(config: CypherCompilerConfiguration, val logger = new StringInfoLogger(log) val monitors = WrappedMonitors(kernelMonitors) - CypherCompilerFactory.costBasedCompiler(config, clock, monitors, logger, rewriterSequencer, - maybePlannerName, maybeRuntimeName, maybeUpdateStrategy, typeConversions, CommunityRuntimeBuilder) + + new CypherCompilerFactory().costBasedCompiler(config, clock, monitors, logger, rewriterSequencer, + maybePlannerName, maybeRuntimeName, maybeUpdateStrategy, typeConversions, runtimeBuilder, contextCreator) } override val queryCacheSize: Int = config.queryCacheSize diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/CartesianProductNotificationAcceptanceTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/CartesianProductNotificationAcceptanceTest.scala index a9ef40edbf903..7f457d4f7a37e 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/CartesianProductNotificationAcceptanceTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/CartesianProductNotificationAcceptanceTest.scala @@ -26,6 +26,7 @@ import org.mockito.Mockito.{verify, _} import org.neo4j.cypher.internal.compatibility.v3_2.{StringInfoLogger, WrappedMonitors} import org.neo4j.cypher.internal.compiler.v3_2._ import org.neo4j.cypher.internal.compiler.v3_2.helpers.IdentityTypeConverter +import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilerContext import org.neo4j.cypher.internal.frontend.v3_2.InputPosition import org.neo4j.cypher.internal.frontend.v3_2.helpers.rewriting.RewriterStepSequencer import org.neo4j.cypher.internal.frontend.v3_2.notification.CartesianProductNotification @@ -35,7 +36,7 @@ import org.neo4j.logging.NullLog class CartesianProductNotificationAcceptanceTest extends CypherFunSuite with GraphDatabaseTestSupport { var logger: InternalNotificationLogger = _ - var compiler: CypherCompiler = _ + var compiler: CypherCompiler[CompilerContext] = _ override protected def beforeEach(): Unit = { super.beforeEach() @@ -96,8 +97,8 @@ class CartesianProductNotificationAcceptanceTest extends CypherFunSuite with Gra } } - private def createCompiler() = { - CypherCompilerFactory.costBasedCompiler( + private def createCompiler(): CypherCompiler[CompilerContext] = { + new CypherCompilerFactory().costBasedCompiler( CypherCompilerConfiguration( queryCacheSize = 128, statsDivergenceThreshold = 0.5, @@ -116,7 +117,8 @@ class CartesianProductNotificationAcceptanceTest extends CypherFunSuite with Gra updateStrategy = None, rewriterSequencer = RewriterStepSequencer.newValidating, runtimeBuilder = CommunityRuntimeBuilder, - typeConverter = IdentityTypeConverter + typeConverter = IdentityTypeConverter, + contextCreator = CommunityContextCreator ) } } diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTestSupport.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTestSupport.scala index cdb34b89dea8f..24a1a87f2095c 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTestSupport.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTestSupport.scala @@ -24,10 +24,10 @@ import java.util.concurrent.TimeUnit import org.hamcrest.CoreMatchers._ import org.junit.Assert._ import org.neo4j.cypher.ExecutionEngineHelper.createEngine -import org.neo4j.cypher.internal._ import org.neo4j.cypher.internal.compiler.v3_2.executionplan.InternalExecutionResult import org.neo4j.cypher.internal.frontend.v3_2.test_helpers.{CypherFunSuite, CypherTestSupport} import org.neo4j.cypher.internal.helpers.GraphIcing +import org.neo4j.cypher.internal.{CompatibilityFactory, ExecutionEngine, RewindableExecutionResult} import org.neo4j.cypher.javacompat.internal.GraphDatabaseCypherService import org.neo4j.graphdb.GraphDatabaseService import org.neo4j.kernel.GraphDatabaseQueryService @@ -86,7 +86,8 @@ object ExecutionEngineHelper { val resolver = graphDatabaseCypherService.getDependencyResolver val kernel = resolver.resolveDependency(classOf[KernelAPI]) val kernelMonitors: KernelMonitors = resolver.resolveDependency(classOf[KernelMonitors]) - val compatibilityFactory = new CommunityCompatibilityFactory(graphDatabaseCypherService, kernel, kernelMonitors, logProvider) + val compatibilityFactory = resolver.resolveDependency( classOf[CompatibilityFactory] ) + new ExecutionEngine(graphDatabaseCypherService, logProvider, compatibilityFactory) } } diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/GraphDatabaseTestSupport.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/GraphDatabaseTestSupport.scala index 1a808d1bce496..4cb9003c46461 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/GraphDatabaseTestSupport.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/GraphDatabaseTestSupport.scala @@ -53,7 +53,7 @@ trait GraphDatabaseTestSupport extends CypherTestSupport with GraphIcing { graph = createGraphDatabase() } - protected def createGraphDatabase() = { + protected def createGraphDatabase(): GraphDatabaseCypherService = { new GraphDatabaseCypherService(new TestGraphDatabaseFactory().newImpermanentDatabase(databaseConfig().asJava)) } diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerAstCacheAcceptanceTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerAstCacheAcceptanceTest.scala index b3b968c75bfe8..cb70fb0d218dc 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerAstCacheAcceptanceTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_2/CypherCompilerAstCacheAcceptanceTest.scala @@ -26,6 +26,7 @@ import org.neo4j.cypher.internal.compatibility.v3_2.{StringInfoLogger, WrappedMo import org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.NO_TRACING import org.neo4j.cypher.internal.compiler.v3_2.executionplan.ExecutionPlan import org.neo4j.cypher.internal.compiler.v3_2.helpers.IdentityTypeConverter +import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilerContext import org.neo4j.cypher.internal.frontend.v3_2.ast.Statement import org.neo4j.cypher.internal.frontend.v3_2.helpers.rewriting.RewriterStepSequencer import org.neo4j.cypher.internal.frontend.v3_2.phases.devNullLogger @@ -39,9 +40,9 @@ import scala.collection.Map class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphDatabaseTestSupport { def createCompiler(queryCacheSize: Int = 128, statsDivergenceThreshold: Double = 0.5, queryPlanTTL: Long = 1000, - clock: Clock = Clock.systemUTC(), log: Log = NullLog.getInstance): CypherCompiler = { + clock: Clock = Clock.systemUTC(), log: Log = NullLog.getInstance): CypherCompiler[CompilerContext] = { - CypherCompilerFactory.costBasedCompiler( + new CypherCompilerFactory().costBasedCompiler( CypherCompilerConfiguration( queryCacheSize, statsDivergenceThreshold, @@ -60,7 +61,8 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData updateStrategy = None, rewriterSequencer = RewriterStepSequencer.newValidating, typeConverter = IdentityTypeConverter, - runtimeBuilder = CommunityRuntimeBuilder + runtimeBuilder = CommunityRuntimeBuilder, + contextCreator = CommunityContextCreator ) } @@ -89,7 +91,7 @@ class CypherCompilerAstCacheAcceptanceTest extends CypherFunSuite with GraphData override def databaseConfig(): Map[Setting[_], String] = Map(GraphDatabaseSettings.cypher_min_replan_interval -> "0") var counter: CacheCounter = _ - var compiler: CypherCompiler = _ + var compiler: CypherCompiler[CompilerContext] = _ override protected def beforeEach(): Unit = { super.beforeEach() diff --git a/community/shell/src/test/java/org/neo4j/shell/TestApps.java b/community/shell/src/test/java/org/neo4j/shell/TestApps.java index 15da29da87f76..ad7bc1cc244fe 100644 --- a/community/shell/src/test/java/org/neo4j/shell/TestApps.java +++ b/community/shell/src/test/java/org/neo4j/shell/TestApps.java @@ -1141,13 +1141,6 @@ public void shouldAllowPlannerAsStartForACypherQuery() throws Exception executeCommand( "CYPHER planner=cost MATCH (n) RETURN n;" ); } - @Test - public void shouldBeAbleToSwitchBetweenRuntimes() throws Exception - { - executeCommand( "CYPHER runtime=compiled MATCH (n)-[:T]-(n) RETURN n;" ); - executeCommand( "CYPHER runtime=interpreted MATCH (n)-[:T]-(n) RETURN n;" ); - } - @Test public void canListAllConfiguration() throws Exception { diff --git a/enterprise/cypher/acceptance-spec-suite/pom.xml b/enterprise/cypher/acceptance-spec-suite/pom.xml index 67fedff668b53..53740cc5ef428 100644 --- a/enterprise/cypher/acceptance-spec-suite/pom.xml +++ b/enterprise/cypher/acceptance-spec-suite/pom.xml @@ -150,23 +150,26 @@ org.neo4j neo4j-cypher ${project.version} - test-jar + + + org.neo4j - neo4j-enterprise-cypher + neo4j-kernel ${project.version} test-jar + test - - org.neo4j - neo4j-kernel + neo4j-enterprise-kernel + ${project.version} test-jar test + org.neo4j neo4j-io @@ -175,6 +178,21 @@ test + + org.neo4j + neo4j-cypher + ${project.version} + test-jar + + + + org.neo4j + neo4j-enterprise-cypher + ${project.version} + test-jar + + + diff --git a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/DumpToStringAcceptanceTest.scala b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/DumpToStringAcceptanceTest.scala index 058a65e15c637..b718e782b43ae 100644 --- a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/DumpToStringAcceptanceTest.scala +++ b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/DumpToStringAcceptanceTest.scala @@ -76,23 +76,26 @@ class DumpToStringAcceptanceTest extends ExecutionEngineFunSuite with NewRuntime } } -trait NewRuntimeTestSupport extends NewPlannerTestSupport with ExecutionEngineTestSupport { - self: ExecutionEngineFunSuite => - override protected def createGraphDatabase(): GraphDatabaseCypherService = { - val impermanentDatabase = new TestEnterpriseGraphDatabaseFactory().newImpermanentDatabase(databaseConfig().asJava) - new GraphDatabaseCypherService(impermanentDatabase) - } - - override protected def initTest(): Unit = { - eengine = createEngine(graph) - } - - def createEngine(graphDatabaseCypherService: GraphDatabaseQueryService, logProvider: LogProvider = NullLogProvider.getInstance()): ExecutionEngine = { - val resolver = graphDatabaseCypherService.getDependencyResolver - val kernel = resolver.resolveDependency(classOf[KernelAPI]) - val kernelMonitors: KernelMonitors = resolver.resolveDependency(classOf[KernelMonitors]) - val communityCompatibilityFactory = new CommunityCompatibilityFactory(graphDatabaseCypherService, kernel, kernelMonitors, logProvider) - val compatibilityFactory = new EnterpriseCompatibilityFactory(communityCompatibilityFactory, graph, kernel, kernelMonitors, logProvider) - new ExecutionEngine(graphDatabaseCypherService, logProvider, compatibilityFactory) - } -} \ No newline at end of file +trait NewRuntimeTestSupport extends NewPlannerTestSupport { + self: ExecutionEngineFunSuite => +} +// with ExecutionEngineTestSupport { +// self: ExecutionEngineFunSuite => +// override protected def createGraphDatabase(): GraphDatabaseCypherService = { +// val impermanentDatabase = new TestEnterpriseGraphDatabaseFactory().newImpermanentDatabase(databaseConfig().asJava) +// new GraphDatabaseCypherService(impermanentDatabase) +// } +// +// override protected def initTest(): Unit = { +// eengine = createEngine(graph) +// } +// +// def createEngine(graphDatabaseCypherService: GraphDatabaseQueryService, logProvider: LogProvider = NullLogProvider.getInstance()): ExecutionEngine = { +// val resolver = graphDatabaseCypherService.getDependencyResolver +// val kernel = resolver.resolveDependency(classOf[KernelAPI]) +// val kernelMonitors: KernelMonitors = resolver.resolveDependency(classOf[KernelMonitors]) +// val communityCompatibilityFactory = new CommunityCompatibilityFactory(graphDatabaseCypherService, kernel, kernelMonitors, logProvider) +// val compatibilityFactory = new EnterpriseCompatibilityFactory(communityCompatibilityFactory, graph, kernel, kernelMonitors, logProvider) +// new ExecutionEngine(graphDatabaseCypherService, logProvider, compatibilityFactory) +// } +//} \ No newline at end of file diff --git a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/LoadCsvAcceptanceTest.scala b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/LoadCsvAcceptanceTest.scala index 715c90abb800c..f02402a917857 100644 --- a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/LoadCsvAcceptanceTest.scala +++ b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/LoadCsvAcceptanceTest.scala @@ -27,10 +27,11 @@ import org.neo4j.cypher._ import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.plans.NodeIndexSeek import org.neo4j.cypher.internal.compiler.v3_2.test_helpers.CreateTempFileTestSupport import org.neo4j.cypher.internal.frontend.v3_2.helpers.StringHelper.RichString +import org.neo4j.graphdb.QueryExecutionException import org.neo4j.graphdb.config.Configuration import org.neo4j.graphdb.factory.GraphDatabaseSettings import org.neo4j.graphdb.security.URLAccessRule -import org.neo4j.test.TestGraphDatabaseFactory +import org.neo4j.test.{TestEnterpriseGraphDatabaseFactory, TestGraphDatabaseFactory} import org.scalatest.BeforeAndAfterAll import scala.collection.JavaConverters._ @@ -392,12 +393,12 @@ class LoadCsvAcceptanceTest } test("should fail for file urls if local file access disallowed") { - val db = new TestGraphDatabaseFactory() + val db = new TestEnterpriseGraphDatabaseFactory() .newImpermanentDatabaseBuilder() .setConfig(GraphDatabaseSettings.allow_file_urls, "false") .newGraphDatabase() - intercept[LoadExternalResourceException] { + intercept[QueryExecutionException] { db.execute(s"LOAD CSV FROM 'file:///tmp/blah.csv' AS line CREATE (a {name:line[0]})", emptyMap()) }.getMessage should endWith(": configuration property 'dbms.security.allow_csv_import_from_file_urls' is false") } @@ -422,12 +423,12 @@ class LoadCsvAcceptanceTest test("should restrict file urls to be rooted within an authorized directory") { val dir = createTempDirectory("loadcsvroot") - val db = new TestGraphDatabaseFactory() + val db = new TestEnterpriseGraphDatabaseFactory() .newImpermanentDatabaseBuilder() .setConfig(GraphDatabaseSettings.load_csv_file_url_root, dir.toString) .newGraphDatabase() - intercept[LoadExternalResourceException] { + intercept[QueryExecutionException] { db.execute(s"LOAD CSV FROM 'file:///../foo.csv' AS line RETURN line[0] AS field", emptyMap()).asScala.size }.getMessage should endWith(" file URL points outside configured import directory") } @@ -554,5 +555,6 @@ class LoadCsvAcceptanceTest httpServer.stop() } - private def createFile(filename: String = "cypher", dir: String = null)(f: PrintWriter => Unit): String = createTempFileURL(filename, ".csv")(f) + private def createFile(filename: String = "cypher", dir: String = null)(f: PrintWriter => Unit): String = + createTempFileURL(filename, ".csv")(f) } diff --git a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/MatchLongPatternAcceptanceTest.scala b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/MatchLongPatternAcceptanceTest.scala index 8838b6df5a9e1..bc754900ea499 100644 --- a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/MatchLongPatternAcceptanceTest.scala +++ b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/MatchLongPatternAcceptanceTest.scala @@ -208,10 +208,10 @@ class MatchLongPatternAcceptanceTest extends ExecutionEngineFunSuite with QueryS runWithConfig(config.toSeq: _*) { (engine, db) => graph = db -// eengine = engine + eengine = engine makeLargeMatrixDataset(100) val monitor = TestIDPSolverMonitor() - val monitors: monitoring.Monitors = graph.getDependencyResolver.resolveDependency(classOf[org.neo4j.kernel.monitoring.Monitors]) + val monitors: monitoring.Monitors = graph.getDependencyResolver.resolveDependency(classOf[monitoring.Monitors]) monitors.addMonitorListener(monitor) val result = innerExecute(s"EXPLAIN CYPHER planner=IDP $query") val counts = countExpandsAndJoins(result.executionPlanDescription()) diff --git a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/QueryPlanCompactionAcceptanceTest.scala b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/QueryPlanCompactionAcceptanceTest.scala index 6bd76941832e3..06cbfe6dec3af 100644 --- a/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/QueryPlanCompactionAcceptanceTest.scala +++ b/enterprise/cypher/acceptance-spec-suite/src/test/scala/org/neo4j/internal/cypher/acceptance/QueryPlanCompactionAcceptanceTest.scala @@ -807,25 +807,25 @@ class QueryPlanCompactionAcceptanceTest extends ExecutionEngineFunSuite with Que relate(d,e) relate(c,b) relate(d,b) - val query = "PROFILE MATCH (n:Actor {name:'Keanu Reeves'})-->()-->(b) RETURN b" + val query = "MATCH (n:Actor {name:'Keanu Reeves'})-->()-->(b) RETURN b" val result = executeWithCostPlannerOnly(query) result should havePlanLike( """ - |+------------------+----------------+------+---------+--------------------------------------+---------------------------+ - || Operator | Estimated Rows | Rows | DB Hits | Variables | Other | - |+------------------+----------------+------+---------+--------------------------------------+---------------------------+ - || +ProduceResults | 1 | 1 | 0 | anon[38], anon[41], anon[43], b, n | | - || | +----------------+------+---------+--------------------------------------+---------------------------+ - || +Filter | 1 | 1 | 0 | anon[38], anon[41], anon[43], b, n | NOT(anon[38] == anon[43]) | - || | +----------------+------+---------+--------------------------------------+---------------------------+ - || +Expand(All) | 1 | 1 | 2 | anon[43], b -- anon[38], anon[41], n | ()-->(b) | - || | +----------------+------+---------+--------------------------------------+---------------------------+ - || +Expand(All) | 1 | 1 | 2 | anon[38], anon[41] -- n | (n)-->() | - || | +----------------+------+---------+--------------------------------------+---------------------------+ - || +Filter | 1 | 1 | 5 | n | n.name == { AUTOSTRING0} | - || | +----------------+------+---------+--------------------------------------+---------------------------+ - || +NodeByLabelScan | 5 | 5 | 6 | n | :Actor | - |+------------------+----------------+------+---------+--------------------------------------+---------------------------+ + |+------------------+----------------+--------------------------------------+---------------------------+ + || Operator | Estimated Rows | Variables | Other | + |+------------------+----------------+--------------------------------------+---------------------------+ + || +ProduceResults | 1 | anon[38], anon[41], anon[43], b, n | | + || | +----------------+--------------------------------------+---------------------------+ + || +Filter | 1 | anon[38], anon[41], anon[43], b, n | NOT(anon[38] == anon[43]) | + || | +----------------+--------------------------------------+---------------------------+ + || +Expand(All) | 1 | anon[43], b -- anon[38], anon[41], n | ()-->(b) | + || | +----------------+--------------------------------------+---------------------------+ + || +Expand(All) | 1 | anon[38], anon[41] -- n | (n)-->() | + || | +----------------+--------------------------------------+---------------------------+ + || +Filter | 1 | n | n.name == { AUTOSTRING0} | + || | +----------------+--------------------------------------+---------------------------+ + || +NodeByLabelScan | 5 | n | :Actor | + |+------------------+----------------+--------------------------------------+---------------------------+ |""".stripMargin) } diff --git a/enterprise/cypher/compatibility-spec-suite/pom.xml b/enterprise/cypher/compatibility-spec-suite/pom.xml index 0883b1859d594..95a5bda155301 100644 --- a/enterprise/cypher/compatibility-spec-suite/pom.xml +++ b/enterprise/cypher/compatibility-spec-suite/pom.xml @@ -140,6 +140,12 @@ test + + org.neo4j + neo4j-enterprise-cypher + ${project.version} + + @@ -150,6 +156,14 @@ test + + org.neo4j + neo4j-enterprise-kernel + ${project.version} + test-jar + test + + org.neo4j neo4j-io @@ -158,6 +172,20 @@ test + + org.neo4j + neo4j-cypher + ${project.version} + test-jar + + + + org.neo4j + neo4j-enterprise-cypher + ${project.version} + test-jar + + org.neo4j neo4j-cypher-spec-suite-tools diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/pom.xml b/enterprise/cypher/cypher-compiled-runtime-3.2/pom.xml index 817b6883bbda1..1d42175d04aca 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/pom.xml +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/pom.xml @@ -116,17 +116,6 @@ neo4j-kernel provided - - org.neo4j - neo4j-io - test-jar - test - - - org.neo4j - neo4j-graph-algo - provided - org.neo4j neo4j-cypher-frontend-3.2 @@ -152,6 +141,13 @@ test + + org.neo4j + neo4j-io + test-jar + test + + org.neo4j neo4j-cypher-frontend-3.2 diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/CompiledRuntimeBuilder.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/CompiledRuntimeBuilder.scala index a7ecaf7cb1a59..99cb16952f688 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/CompiledRuntimeBuilder.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/CompiledRuntimeBuilder.scala @@ -24,11 +24,9 @@ import org.neo4j.cypher.internal.compiler.v3_2.phases.{Do, If, Transformer} import org.neo4j.cypher.internal.frontend.v3_2.InvalidArgumentException import org.neo4j.cypher.internal.frontend.v3_2.notification.RuntimeUnsupportedNotification -class CompiledRuntimeBuilder extends RuntimeBuilder[CompiledRuntimeContext] { +class CompiledRuntimeBuilder extends RuntimeBuilder[Transformer[CompiledRuntimeContext]] { - type C = CompiledRuntimeContext - - def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): Transformer[C] = + override def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): Transformer[CompiledRuntimeContext] = runtimeName match { case None => BuildCompiledExecutionPlan andThen @@ -48,11 +46,11 @@ class CompiledRuntimeBuilder extends RuntimeBuilder[CompiledRuntimeContext] { case Some(CompiledRuntimeName) => BuildCompiledExecutionPlan andThen If(_.maybeExecutionPlan.isEmpty)( - Do((ctx: C) => warnThatCompiledRuntimeDoesNotYetSupportQuery(ctx)) andThen + Do((ctx: CompiledRuntimeContext) => warnThatCompiledRuntimeDoesNotYetSupportQuery(ctx)) andThen BuildInterpretedExecutionPlan ) } - private def warnThatCompiledRuntimeDoesNotYetSupportQuery(ctx: C) = + private def warnThatCompiledRuntimeDoesNotYetSupportQuery(ctx: CompiledRuntimeContext) = ctx.notificationLogger.log(RuntimeUnsupportedNotification) } diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/BuildSortTable.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/BuildSortTable.scala index e2cd50a165962..b4ce2362de5aa 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/BuildSortTable.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/BuildSortTable.scala @@ -5,17 +5,17 @@ * 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. + * it under the terms of the GNU Affero 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. + * GNU Affero 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/GetSortedResult.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/GetSortedResult.scala index 8edb76d7e7ce2..9294215008d8f 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/GetSortedResult.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/GetSortedResult.scala @@ -5,17 +5,17 @@ * 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. + * it under the terms of the GNU Affero 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. + * GNU Affero 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/SortInstruction.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/SortInstruction.scala index 984498992f7ab..2f73e554b9eb5 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/SortInstruction.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/SortInstruction.scala @@ -5,17 +5,17 @@ * 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. + * it under the terms of the GNU Affero 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. + * GNU Affero 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindCollection.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindCollection.scala index d9c00ba33a1d8..27e2e35e2997e 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindCollection.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindCollection.scala @@ -5,17 +5,17 @@ * 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. + * it under the terms of the GNU Affero 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. + * GNU Affero 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindPrimitiveCollection.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindPrimitiveCollection.scala index 275891e774d15..c730e6f0960aa 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindPrimitiveCollection.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/UnwindPrimitiveCollection.scala @@ -5,17 +5,17 @@ * 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. + * it under the terms of the GNU Affero 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. + * GNU Affero 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir diff --git a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/expressions/MapProperty.scala b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/expressions/MapProperty.scala index 4dc5f7f5c9eef..a2436ad1becd0 100644 --- a/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/expressions/MapProperty.scala +++ b/enterprise/cypher/cypher-compiled-runtime-3.2/src/main/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/expressions/MapProperty.scala @@ -5,17 +5,17 @@ * 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. + * it under the terms of the GNU Affero 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. + * GNU Affero 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir.expressions diff --git a/enterprise/cypher/cypher/pom.xml b/enterprise/cypher/cypher/pom.xml index 484f6eec4a954..75008ce398d5f 100644 --- a/enterprise/cypher/cypher/pom.xml +++ b/enterprise/cypher/cypher/pom.xml @@ -150,6 +150,18 @@ test-jar test + + org.neo4j + neo4j-io + test-jar + test + + + org.neo4j + neo4j-common + test-jar + test + org.neo4j neo4j-enterprise-kernel diff --git a/enterprise/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/EnterpriseCypherEngineProvider.java b/enterprise/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/EnterpriseCypherEngineProvider.java index 1a3a6cc0afa02..32cbc128edd13 100644 --- a/enterprise/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/EnterpriseCypherEngineProvider.java +++ b/enterprise/cypher/cypher/src/main/java/org/neo4j/cypher/internal/javacompat/EnterpriseCypherEngineProvider.java @@ -63,7 +63,7 @@ protected QueryExecutionEngine createEngine( Dependencies deps, GraphDatabaseAPI EnterpriseCompatibilityFactory compatibilityFactory = new EnterpriseCompatibilityFactory( inner, queryService, kernelAPI, monitors, logProvider ); - + deps.satisfyDependency( compatibilityFactory ); return new ExecutionEngine( queryService, logProvider, compatibilityFactory ); } } diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseCompatibilityFactory.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseCompatibilityFactory.scala index 1da879df0b3df..83809c1bc3d45 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseCompatibilityFactory.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseCompatibilityFactory.scala @@ -20,8 +20,10 @@ package org.neo4j.cypher.internal import org.neo4j.cypher.internal.compatibility.{v2_3, v3_1, _} -import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration -import org.neo4j.cypher.{CypherPlanner, CypherRuntime} +import org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.{ByteCodeMode, CodeGenConfiguration, CodeGenMode, SourceCodeMode} +import org.neo4j.cypher.internal.compiler.v3_2._ +import org.neo4j.cypher.internal.spi.v3_2.codegen.GeneratedQueryStructure +import org.neo4j.cypher.{CypherCodeGenMode, CypherPlanner, CypherRuntime} import org.neo4j.kernel.GraphDatabaseQueryService import org.neo4j.kernel.api.KernelAPI import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} @@ -36,13 +38,23 @@ class EnterpriseCompatibilityFactory(inner: CompatibilityFactory, graph: GraphDa override def create(spec: PlannerSpec_v3_1, config: CypherCompilerConfiguration): v3_1.Compatibility = inner.create(spec, config) - override def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility = + override def create(spec: PlannerSpec_v3_2, config: CypherCompilerConfiguration): v3_2.Compatibility[_] = (spec.planner, spec.runtime) match { case (CypherPlanner.rule, _) => inner.create(spec, config) case (_, CypherRuntime.compiled) | (_, CypherRuntime.default) => - v3_2.CostCompatibility(config, CompilerEngineDelegator.CLOCK, kernelMonitors, kernelAPI, - logProvider.getLog(getClass), spec.planner, spec.runtime, spec.codeGenMode, spec.updateStrategy) + + val codeGenMode = spec.codeGenMode match { + case CypherCodeGenMode.default => CodeGenMode.default + case CypherCodeGenMode.byteCode => ByteCodeMode + case CypherCodeGenMode.sourceCode => SourceCodeMode + } + + val codeGenConfiguration: CodeGenConfiguration = CodeGenConfiguration(mode = codeGenMode) + + val contextCreator = new EnterpriseContextCreator(GeneratedQueryStructure, codeGenConfiguration) + v3_2.CostCompatibility(config, CompilerEngineDelegator.CLOCK, kernelMonitors, kernelAPI, logProvider.getLog + (getClass), spec.planner, spec.runtime, spec.updateStrategy, EnterpriseRuntimeBuilder, contextCreator) case _ => inner.create(spec, config) } diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseContextCreator.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseContextCreator.scala new file mode 100644 index 0000000000000..256fd9fea0592 --- /dev/null +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseContextCreator.scala @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.cypher.internal + +import java.time.Clock + +import org.neo4j.cypher.internal.compiled_runtime.v3_2.CompiledRuntimeContext +import org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.CodeGenConfiguration +import org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.spi.CodeStructure +import org.neo4j.cypher.internal.compiled_runtime.v3_2.executionplan.GeneratedQuery +import org.neo4j.cypher.internal.compiler.v3_2.executionplan.{PlanFingerprint, PlanFingerprintReference} +import org.neo4j.cypher.internal.compiler.v3_2.helpers.RuntimeTypeConverter +import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.{Metrics, MetricsFactory, QueryGraphSolver} +import org.neo4j.cypher.internal.compiler.v3_2.spi.PlanContext +import org.neo4j.cypher.internal.compiler.v3_2.{ContextCreator, CypherCompilerConfiguration, SyntaxExceptionCreator, UpdateStrategy} +import org.neo4j.cypher.internal.frontend.v3_2.InputPosition +import org.neo4j.cypher.internal.frontend.v3_2.phases.{CompilationPhaseTracer, InternalNotificationLogger, Monitors} + +class EnterpriseContextCreator(codeStructure: CodeStructure[GeneratedQuery], codeGenConfiguration: CodeGenConfiguration) extends ContextCreator[CompiledRuntimeContext] { + override def create(tracer: CompilationPhaseTracer, + notificationLogger: InternalNotificationLogger, + planContext: PlanContext, + queryText: String, + offset: Option[InputPosition], + monitors: Monitors, + createFingerprintReference: Option[PlanFingerprint] => PlanFingerprintReference, + typeConverter: RuntimeTypeConverter, + metricsFactory: MetricsFactory, + queryGraphSolver: QueryGraphSolver, + config: CypherCompilerConfiguration, + updateStrategy: UpdateStrategy, + clock: Clock): CompiledRuntimeContext = { + val exceptionCreator = new SyntaxExceptionCreator(queryText, offset) + + val metrics: Metrics = if (planContext == null) + null + else + metricsFactory.newMetrics(planContext.statistics) + + new CompiledRuntimeContext(exceptionCreator, tracer, notificationLogger, planContext, typeConverter, createFingerprintReference, + monitors, metrics, queryGraphSolver, config, updateStrategy, clock, codeStructure, codeGenConfiguration) + } +} diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseRuntimeBuilder.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseRuntimeBuilder.scala new file mode 100644 index 0000000000000..1d3ba7f66db36 --- /dev/null +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/EnterpriseRuntimeBuilder.scala @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.cypher.internal + +import org.neo4j.cypher.internal.compiled_runtime.v3_2.{BuildCompiledExecutionPlan, CompiledRuntimeContext} +import org.neo4j.cypher.internal.compiler.v3_2._ +import org.neo4j.cypher.internal.compiler.v3_2.phases.{Do, If, Transformer} +import org.neo4j.cypher.internal.frontend.v3_2.InvalidArgumentException +import org.neo4j.cypher.internal.frontend.v3_2.notification.RuntimeUnsupportedNotification + +object EnterpriseRuntimeBuilder extends RuntimeBuilder[Transformer[CompiledRuntimeContext]] { + def create(runtimeName: Option[RuntimeName], useErrorsOverWarnings: Boolean): Transformer[CompiledRuntimeContext] = runtimeName match { + case None => + BuildCompiledExecutionPlan andThen + If(_.maybeExecutionPlan.isEmpty) { + BuildInterpretedExecutionPlan + } + + case Some(InterpretedRuntimeName) => + BuildInterpretedExecutionPlan + + case Some(CompiledRuntimeName) if useErrorsOverWarnings => + BuildCompiledExecutionPlan andThen + If(_.maybeExecutionPlan.isEmpty)( + Do(_ => throw new InvalidArgumentException("The given query is not currently supported in the selected runtime")) + ) + + case Some(CompiledRuntimeName) => + BuildCompiledExecutionPlan andThen + If(_.maybeExecutionPlan.isEmpty)( + Do((_: CompiledRuntimeContext).notificationLogger.log(RuntimeUnsupportedNotification)) andThen + BuildInterpretedExecutionPlan + ) + + case Some(x) => throw new InvalidArgumentException(s"This version of Neo4j does not support requested runtime: $x") + } +} diff --git a/enterprise/cypher/cypher/src/test/java/org/neo4j/cypher/internal/javacompact/ExecutionResultTest.java b/enterprise/cypher/cypher/src/test/java/org/neo4j/cypher/internal/javacompat/ExecutionResultTest.java similarity index 95% rename from enterprise/cypher/cypher/src/test/java/org/neo4j/cypher/internal/javacompact/ExecutionResultTest.java rename to enterprise/cypher/cypher/src/test/java/org/neo4j/cypher/internal/javacompat/ExecutionResultTest.java index 22f86e854a306..24ebc8828f688 100644 --- a/enterprise/cypher/cypher/src/test/java/org/neo4j/cypher/internal/javacompact/ExecutionResultTest.java +++ b/enterprise/cypher/cypher/src/test/java/org/neo4j/cypher/internal/javacompat/ExecutionResultTest.java @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package org.neo4j.cypher.internal.javacompact; +package org.neo4j.cypher.internal.javacompat; import org.junit.Rule; import org.junit.Test; @@ -29,7 +29,7 @@ import org.neo4j.graphdb.Result; import org.neo4j.graphdb.Transaction; import org.neo4j.helpers.collection.Iterators; -import org.neo4j.test.rule.ImpermanentDatabaseRule; +import org.neo4j.test.rule.EnterpriseDatabaseRule; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; @@ -38,7 +38,7 @@ public class ExecutionResultTest { @Rule - public final ImpermanentDatabaseRule db = new ImpermanentDatabaseRule(); + public final EnterpriseDatabaseRule db = new EnterpriseDatabaseRule(); @Test public void shouldBePossibleToConsumeCompiledExecutionResultsWithIterator() diff --git a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineIT.scala b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineIT.scala index 291eb4f7f8657..9c00bbaf31422 100644 --- a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineIT.scala +++ b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineIT.scala @@ -79,7 +79,7 @@ class ExecutionEngineIT extends CypherFunSuite with GraphIcing { val emptySignature: util.List[FieldSignature] = List.empty[FieldSignature].asJava val signature: ProcedureSignature = new ProcedureSignature( procedureName, paramSignature, resultSignature, Mode.READ, java.util.Optional.empty(), Array.empty, - java.util.Optional.empty()) + java.util.Optional.empty(), java.util.Optional.empty()) def paramSignature: util.List[FieldSignature] = List.empty[FieldSignature].asJava diff --git a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala index 552e23de35c43..2fde1286b2265 100644 --- a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala +++ b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala @@ -28,6 +28,7 @@ import org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.Com import org.neo4j.cypher.internal.compiler.v3_2.test_helpers.CreateTempFileTestSupport import org.neo4j.cypher.internal.tracing.TimingCompilationTracer import org.neo4j.cypher.internal.tracing.TimingCompilationTracer.QueryEvent +import org.neo4j.cypher.javacompat.internal.GraphDatabaseCypherService import org.neo4j.graphdb._ import org.neo4j.graphdb.config.Setting import org.neo4j.graphdb.factory.GraphDatabaseSettings @@ -36,7 +37,7 @@ import org.neo4j.kernel.NeoStoreDataSource import org.neo4j.kernel.api.KernelTransaction.Type import org.neo4j.kernel.api.security.AnonymousContext import org.neo4j.kernel.impl.coreapi.TopLevelTransaction -import org.neo4j.test.TestGraphDatabaseFactory +import org.neo4j.test.{TestEnterpriseGraphDatabaseFactory, TestGraphDatabaseFactory} import scala.collection.JavaConverters._ import scala.collection.mutable @@ -965,6 +966,10 @@ order by a.COL1""") result should have size 2 } + override protected def createGraphDatabase(): GraphDatabaseCypherService = { + new GraphDatabaseCypherService(new TestEnterpriseGraphDatabaseFactory().newImpermanentDatabase(databaseConfig().asJava)) + } + override def databaseConfig(): Map[Setting[_], String] = super.databaseConfig() ++ Map( GraphDatabaseSettings.cypher_min_replan_interval -> "0", GraphDatabaseSettings.cypher_compiler_tracing -> "true" @@ -1042,9 +1047,9 @@ order by a.COL1""") private def createReadOnlyEngine(): ExecutionEngine = { FileUtils.deleteRecursively(new File("target/readonly")) - val old = new TestGraphDatabaseFactory().newEmbeddedDatabase( new File( "target/readonly" ) ) + val old = new TestEnterpriseGraphDatabaseFactory().newEmbeddedDatabase( new File( "target/readonly" ) ) old.shutdown() - val db = new TestGraphDatabaseFactory().newEmbeddedDatabaseBuilder( new File( "target/readonly" ) ) + val db = new TestEnterpriseGraphDatabaseFactory().newEmbeddedDatabaseBuilder( new File( "target/readonly" ) ) .setConfig( GraphDatabaseSettings.read_only, "true" ) .newGraphDatabase() createEngine(db) diff --git a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/CodeGenExpressionCompilationTest.scala b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/CodeGenExpressionCompilationTest.scala index 2f55223927942..75cf4e9494dd7 100644 --- a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/CodeGenExpressionCompilationTest.scala +++ b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/v3_2/codegen/ir/CodeGenExpressionCompilationTest.scala @@ -20,8 +20,7 @@ package org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir import org.neo4j.cypher.internal.compiled_runtime.v3_2.codegen.ir.expressions._ -import org.neo4j.cypher.internal.frontend.v3_2 -import org.neo4j.cypher.internal.frontend.v3_2.CypherTypeException +import org.neo4j.cypher.internal.frontend.v3_2.{ArithmeticException, CypherTypeException} import org.neo4j.cypher.internal.frontend.v3_2.test_helpers.CypherFunSuite import org.scalatest._ diff --git a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/CypherCompilerPerformanceTest.scala b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/CypherCompilerPerformanceTest.scala deleted file mode 100644 index f398f27a111c3..0000000000000 --- a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/CypherCompilerPerformanceTest.scala +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.neo4j.cypher.internal.compiler - -import org.neo4j.cypher.GraphDatabaseFunSuite -import org.neo4j.cypher.internal.CompilerEngineDelegator.{CLOCK, DEFAULT_QUERY_PLAN_TTL, DEFAULT_STATISTICS_DIVERGENCE_THRESHOLD} -import org.neo4j.cypher.internal.compatibility.v3_2.WrappedMonitors -import org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.NO_TRACING -import org.neo4j.cypher.internal.compiler.v3_2.helpers.IdentityTypeConverter -import org.neo4j.cypher.internal.compiler.v3_2.phases.CompilationState -import org.neo4j.cypher.internal.compiler.v3_2.{CypherCompilerFactory, InfoLogger, _} -import org.neo4j.cypher.internal.frontend.v3_2.helpers.rewriting.RewriterStepSequencer -import org.neo4j.cypher.internal.frontend.v3_2.phases.devNullLogger - -import scala.concurrent.duration._ - -class CypherCompilerPerformanceTest extends GraphDatabaseFunSuite { - - val NUMBER_OF_RUNS = 10 - - val warmup = - """MATCH (n:Person)-[:KNOWS]->(c:City) - |WITH DISTINCT n, count(*) AS count - |MATCH (n)-[:KNOWS*..5]->(f:Person)-[:LIVES_IN]->(:City {name: "Berlin"}) - |WHERE (f)-[:LOVES]->(:Girl) - |RETURN n, count, collect(f) AS friends""".stripMargin - - val foo1 = - """match - | (toFrom:Duck{Id:{duckId}}), - | (brook)-[:precedes|is]->(startbrook), - | (toFrom)-[toFrom_rel:wiggle|quack]->(startbrook) - |with brook - |match (brook)-[:regarding_summary_phrase]->(Duck) - |with brook, Duck - |match (checkUnpopularDuck)-[:quack]->(brook) - |where ((checkUnpopularDuck.Rank > 0 or checkUnpopularDuck.Rank is null)) and ((Duck.Rank > 0 or Duck.Rank is null)) and (NOT(Duck.Id = {duckId})) - |RETURN Duck.Id as Id, Duck.Name as Name, Duck.Type as Type, Duck.MentionNames as Mentions, count(distinct brook) as brookCount - |order by brookCount desc skip 0 limit 51""".stripMargin - - val foo2 = - """match - | (toFrom:Duck{Id:{duckId}}), - | (toFrom)-[toFrom_rel:wiggle|quack]->(brook:brook), - | (copy)-[:of]->(bridge)-[bridgebrook:containing]->(brook), - | (brook)-[:in_thicket]->(thicket:Thicket), - | (checkUnpopularDuck:Duck)-[:quack]->(brook) - |where (checkUnpopularDuck.Rank > 0 or checkUnpopularDuck.Rank is null) - |return count(distinct thicket) as ThicketCount, count(distinct brook) as brookCount - |skip 0""".stripMargin - - val socnet1 = - """MATCH (subject:User {name:{name}}) - |MATCH p=(subject)-[:WORKED_ON]->()<-[:WORKED_ON]-(person)-[:INTERESTED_IN]->(interest) - |WHERE person<>subject AND interest.name={topic} - |WITH DISTINCT person.name AS name, min(length(p)) as pathLength - |ORDER BY pathLength ASC LIMIT 10 RETURN name, pathLength - |UNION - |MATCH (subject:User {name:{name}}) - |MATCH p=(subject)-[:WORKED_ON]->()-[:WORKED_ON]-()<-[:WORKED_ON]-(person)-[:INTERESTED_IN]->(interest) - |WHERE person<>subject AND interest.name={topic} - |WITH DISTINCT person.name AS name, min(length(p)) as pathLength - |ORDER BY pathLength ASC LIMIT 10 RETURN name, pathLength - |UNION - |MATCH (subject:User {name:{name}}) - |MATCH p=(subject)-[:WORKED_ON]->()-[:WORKED_ON]-()-[:WORKED_ON]-()<-[:WORKED_ON]-(person)-[:INTERESTED_IN]->(interest) - |WHERE person<>subject AND interest.name={topic} - |WITH DISTINCT person.name AS name, min(length(p)) as pathLength - |ORDER BY pathLength ASC LIMIT 10 - |RETURN name, pathLength""".stripMargin - - val socnet9 = - """MATCH (subject:User {name:{name}}) - |MATCH p=(subject)-[:WORKED_WITH*0..1]-()-[:WORKED_WITH]-(person)-[:INTERESTED_IN]->(interest) - |WHERE person<>subject AND interest.name IN {interests} - |WITH person, interest, min(length(p)) as pathLength - |RETURN person.name AS name, count(interest) AS score, collect(interest.name) AS interests, (pathLength - 1) AS distance - |ORDER BY score DESC LIMIT 20""".stripMargin - - val qmul1 = - """MATCH (a:Person)-->(m)-[r]->(n)-->(a) - |WHERE a.uid IN ['1195630902','1457065010'] AND exists(m.location_lat) AND exists(n.location_lat) - |RETURN count(r)""".stripMargin - - test("plans are built fast enough") { - val queries = List(foo1, foo2, socnet1, socnet9, qmul1) - plan(NUMBER_OF_RUNS)(warmup) - - queries.foreach(assertIsPlannedTimely) - } - - private def assertIsPlannedTimely(query: String) = { - val result = plan(NUMBER_OF_RUNS)(query) - - withClue("Planning of the first query took too long:\n" + result.description) { - result.prepareAndPlanFirstNanos shouldBe <(3.second.toNanos) - } - - withClue("Median planning took too long:\n" + result.description) { - result.prepareAndPlanMedianNanos shouldBe <(1.5.second.toNanos) - } - } - - def plan(times: Int)(query: String): PlanningResult = { - val prepareAndPlanTimes = (1 to times).map(i => plan(query)).toArray - - val totalTimes = prepareAndPlanTimes.map(t => t._1 + t._2) - val prepareTimes = prepareAndPlanTimes.map(_._1) - val planTimes = prepareAndPlanTimes.map(_._2) - - val (prepareFirst, planFirst) = prepareAndPlanTimes(0) - - val totalMedian = median(totalTimes) - val prepareMedian = median(prepareTimes) - val planMedian = median(planTimes) - - val description = - s""" - |* Planned query:\n\n${indent(query)}\n - | * First prepare time: ${ms(prepareFirst)} - | * First plan time: ${ms(planFirst)} - | * First total time: ${ms(prepareFirst + planFirst)} - | * Number of runs: $times - | * Median prepare time: ${ms(prepareMedian)} - | * Median planning time: ${ms(planMedian)} - | * Median total time: ${ms(totalMedian)} - | - | * Prepare times: ${ms(prepareTimes)} - | * Plan times: ${ms(planTimes)} - | * Total times: ${ms(totalTimes)} - """.stripMargin - - PlanningResult(description, totalTimes(0), totalMedian) - } - - def ms(valueNanos: Long): String = valueNanos.nanos.toMillis + "ms" - - def ms(valuesNanos: Seq[Long]): String = valuesNanos.map(ms).mkString(", ") - - def median(values: Seq[Long]): Long = { - val sorted = values.sorted - val mid = sorted.size / 2 - if (sorted.size % 2 != 0) - sorted(mid) - else - (sorted(mid - 1) + sorted(mid)) / 2 - } - - private def indent(text: String, indent: String = " ") = - indent + text.replace("\n", s"\n$indent") - - def plan(query: String): (Long, Long) = { - val compiler = createCurrentCompiler - val (preparedSyntacticQueryTime, preparedSyntacticQuery: CompilationState) = measure(compiler.parseQuery(query, query, devNullLogger, IDPPlannerName.name, None, NO_TRACING)) - val planTime = graph.withTx { tx => - val (planTime, _) = measure(compiler.planPreparedQuery(preparedSyntacticQuery, devNullLogger, planContext, None, NO_TRACING)) - planTime - } - (preparedSyntacticQueryTime, planTime) - } - - def measure[T](f: => T): (Long, T) = { - val start = System.nanoTime() - val result = f - val stop = System.nanoTime() - (stop - start, result) - } - - private def createCurrentCompiler = { - CypherCompilerFactory.costBasedCompiler( - CypherCompilerConfiguration( - queryCacheSize = 1, - statsDivergenceThreshold = DEFAULT_STATISTICS_DIVERGENCE_THRESHOLD, - queryPlanTTL = DEFAULT_QUERY_PLAN_TTL, - useErrorsOverWarnings = false, - idpMaxTableSize = 128, - idpIterationDuration = 1000, - errorIfShortestPathFallbackUsedAtRuntime = false, - nonIndexedLabelWarningThreshold = 10000L - ), - clock = CLOCK, - monitors = WrappedMonitors(kernelMonitors), - logger = DEV_NULL, - rewriterSequencer = RewriterStepSequencer.newPlain, - plannerName = Some(IDPPlannerName), - runtimeName = Some(CompiledRuntimeName), - updateStrategy = None, - typeConverter = IdentityTypeConverter, - runtimeBuilder = CommunityRuntimeBuilder - ) - } - - object DEV_NULL extends InfoLogger { - def info(message: String){} - } - - case class PlanningResult(description: String, prepareAndPlanFirstNanos: Long, prepareAndPlanMedianNanos: Long) - -} diff --git a/enterprise/cypher/spec-suite-tools/pom.xml b/enterprise/cypher/spec-suite-tools/pom.xml index 975f7a79a30b9..745eef5637931 100644 --- a/enterprise/cypher/spec-suite-tools/pom.xml +++ b/enterprise/cypher/spec-suite-tools/pom.xml @@ -161,7 +161,8 @@ org.neo4j - neo4j-kernel + neo4j-enterprise-kernel + ${project.version} @@ -175,6 +176,15 @@ org.neo4j neo4j-kernel + ${project.version} + test-jar + test + + + + org.neo4j + neo4j-enterprise-kernel + ${project.version} test-jar test diff --git a/enterprise/cypher/spec-suite-tools/src/test/scala/cypher/feature/steps/SpecSuiteSteps.scala b/enterprise/cypher/spec-suite-tools/src/test/scala/cypher/feature/steps/SpecSuiteSteps.scala index da4ce94507853..ba1624afd2653 100644 --- a/enterprise/cypher/spec-suite-tools/src/test/scala/cypher/feature/steps/SpecSuiteSteps.scala +++ b/enterprise/cypher/spec-suite-tools/src/test/scala/cypher/feature/steps/SpecSuiteSteps.scala @@ -29,7 +29,7 @@ import cypher.feature.parser._ import cypher.feature.parser.matchers.ResultWrapper import org.neo4j.collection.RawIterator import org.neo4j.cypher.internal.frontend.v3_2.symbols.{CypherType, _} -import org.neo4j.graphdb.factory.{GraphDatabaseFactory, GraphDatabaseSettings} +import org.neo4j.graphdb.factory.{EnterpriseGraphDatabaseFactory, GraphDatabaseFactory, GraphDatabaseSettings} import org.neo4j.graphdb.{GraphDatabaseService, QueryStatistics, Result, Transaction} import org.neo4j.kernel.api.KernelAPI import org.neo4j.kernel.api.exceptions.ProcedureException @@ -37,7 +37,7 @@ import org.neo4j.kernel.api.proc.CallableProcedure.BasicProcedure import org.neo4j.kernel.api.proc.{Context, Neo4jTypes} import org.neo4j.kernel.internal.GraphDatabaseAPI import org.neo4j.procedure.Mode -import org.neo4j.test.TestGraphDatabaseFactory +import org.neo4j.test.{TestEnterpriseGraphDatabaseFactory, TestGraphDatabaseFactory} import org.opencypher.tools.tck.TCKCucumberTemplate import org.opencypher.tools.tck.constants.TCKStepDefinitions._ import org.scalatest.{FunSuiteLike, Matchers} @@ -176,7 +176,7 @@ trait SpecSuiteSteps extends FunSuiteLike with Matchers with TCKCucumberTemplate val config = currentDatabaseConfig(pcSize.toString) val archiveUse = GraphArchive(recipe, config).readOnlyUse val path = graphArchiveLibrary.lendForReadOnlyUse(archiveUse)(graphImporter) - val builder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(path.jfile) + val builder = new EnterpriseGraphDatabaseFactory().newEmbeddedDatabaseBuilder(path.jfile) builder.setConfig(archiveUse.dbConfig.asJava) builder.newGraphDatabase().asInstanceOf[GraphDatabaseAPI] } @@ -241,7 +241,7 @@ trait SpecSuiteSteps extends FunSuiteLike with Matchers with TCKCucumberTemplate object graphImporter extends GraphArchiveImporter { protected def createDatabase(archive: GraphArchive.Descriptor, destination: Path): GraphDatabaseService = { - val builder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(destination.jfile) + val builder = new EnterpriseGraphDatabaseFactory().newEmbeddedDatabaseBuilder(destination.jfile) builder.setConfig(archive.dbConfig.asJava) builder.newGraphDatabase() } @@ -250,9 +250,9 @@ trait SpecSuiteSteps extends FunSuiteLike with Matchers with TCKCucumberTemplate object DbBuilder { def initEmpty(config: Map[String, String]): GraphDatabaseAPI = { - val builder = new TestGraphDatabaseFactory().newImpermanentDatabaseBuilder() - builder.setConfig(config.asJava) - builder.newGraphDatabase().asInstanceOf[GraphDatabaseAPI] + val builder = new TestEnterpriseGraphDatabaseFactory().newImpermanentDatabaseBuilder() + builder.setConfig(config.asJava) + builder.newGraphDatabase().asInstanceOf[GraphDatabaseAPI] } /**