Skip to content

Commit

Permalink
Deprecate START
Browse files Browse the repository at this point in the history
Deprecate START and provide a notifications detailing how to rewrite
the query.
  • Loading branch information
pontusmelke committed Jun 15, 2017
1 parent 7cf92a7 commit 7ca2954
Show file tree
Hide file tree
Showing 17 changed files with 316 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package org.neo4j.cypher.internal.compiler.v3_3.ast.rewriters
import org.neo4j.cypher.internal.compiler.v3_3._
import org.neo4j.cypher.internal.frontend.v3_3.ast.Statement
import org.neo4j.cypher.internal.frontend.v3_3.test_helpers.CypherFunSuite
import org.neo4j.cypher.internal.frontend.v3_3.{DummyPosition, Rewriter, SemanticChecker}
import org.neo4j.cypher.internal.frontend.v3_3.{Rewriter, SemanticChecker}

trait RewriteTest {
self: CypherFunSuite =>
Expand All @@ -34,14 +34,12 @@ trait RewriteTest {
protected def assertRewrite(originalQuery: String, expectedQuery: String) {
val original = parseForRewriting(originalQuery)
val expected = parseForRewriting(expectedQuery)
val mkException = new SyntaxExceptionCreator(originalQuery, Some(DummyPosition(0)))
SemanticChecker.check(original, SyntaxExceptionCreator.throwOnError(mkException))

SemanticChecker.check(original)
val result = rewrite(original)
assert(result === expected, "\n" + originalQuery)
}

protected def parseForRewriting(queryText: String) = parser.parse(queryText.replace("\r\n", "\n"))
protected def parseForRewriting(queryText: String): Statement = parser.parse(queryText.replace("\r\n", "\n"))

protected def rewrite(original: Statement): AnyRef =
original.rewrite(rewriterUnderTest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ import org.neo4j.cypher.internal.frontend.v3_3.ast.Query
import org.neo4j.cypher.internal.frontend.v3_3.ast.rewriters.flattenBooleanOperators
import org.neo4j.cypher.internal.frontend.v3_3.helpers.fixedPoint
import org.neo4j.cypher.internal.frontend.v3_3.test_helpers.CypherFunSuite
import org.neo4j.cypher.internal.frontend.v3_3.{DummyPosition, SemanticChecker, SemanticTable}
import org.neo4j.cypher.internal.frontend.v3_3.{DummyPosition, Rewriter, SemanticChecker, SemanticTable}
import org.neo4j.cypher.internal.ir.v3_3.UnionQuery

class OptionalMatchRemoverTest extends CypherFunSuite with LogicalPlanningTestSupport2 {

val rewriter = OptionalMatchRemover.instance(null)
val rewriter: Rewriter = OptionalMatchRemover.instance(null)

assert_that(
"""MATCH (a)
Expand Down Expand Up @@ -197,8 +197,10 @@ class OptionalMatchRemoverTest extends CypherFunSuite with LogicalPlanningTestSu
private def getUnionQueryFrom(query: String): UnionQuery = {
val ast = parseForRewriting(query).endoRewrite(flattenBooleanOperators)
val mkException = new SyntaxExceptionCreator(query, Some(DummyPosition(0)))
val semanticState = SemanticChecker.check(ast, SyntaxExceptionCreator.throwOnError(mkException))
val table = SemanticTable(types = semanticState.typeTable, recordedScopes = semanticState.recordedScopes)
val onError = SyntaxExceptionCreator.throwOnError(mkException)
val result = SemanticChecker.check(ast)
onError(result.errors)
val table = SemanticTable(types = result.state.typeTable, recordedScopes = result.state.recordedScopes)
toUnionQuery(ast.asInstanceOf[Query], table)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.neo4j.cypher.internal.compiler.v3_3.test_helpers.ContextHelper
import org.neo4j.cypher.internal.frontend.v3_3.ast.rewriters._
import org.neo4j.cypher.internal.frontend.v3_3.ast.{Query, Statement}
import org.neo4j.cypher.internal.frontend.v3_3.phases.LateAstRewriting
import org.neo4j.cypher.internal.frontend.v3_3.{SemanticChecker, SemanticTable, inSequence}
import org.neo4j.cypher.internal.frontend.v3_3.{SemanticCheckResult, SemanticChecker, SemanticTable, inSequence}
import org.neo4j.cypher.internal.ir.v3_3.{PlannerQuery, QueryGraph}
import org.scalatest.mock.MockitoSugar

Expand All @@ -41,14 +41,16 @@ trait QueryGraphProducer extends MockitoSugar {
val ast = parser.parse(q)
val mkException = new SyntaxExceptionCreator(query, Some(pos))
val cleanedStatement: Statement = ast.endoRewrite(inSequence(normalizeReturnClauses(mkException), normalizeWithClauses(mkException)))
val semanticState = SemanticChecker.check(cleanedStatement, SyntaxExceptionCreator.throwOnError(mkException))
val onError = SyntaxExceptionCreator.throwOnError(mkException)
val SemanticCheckResult(semanticState, errors) = SemanticChecker.check(cleanedStatement)
onError(errors)

val (firstRewriteStep, _, _) = astRewriter.rewrite(query, cleanedStatement, semanticState)
val state = LogicalPlanState(query, None, IDPPlannerName, Some(firstRewriteStep), Some(semanticState))
val context = ContextHelper.create()
val output = (Namespacer andThen rewriteEqualityToInPredicate andThen CNFNormalizer andThen LateAstRewriting).transform(state, context)

(toUnionQuery(output.statement.asInstanceOf[Query], output.semanticTable).queries.head, output.semanticTable)
(toUnionQuery(output.statement().asInstanceOf[Query], output.semanticTable()).queries.head, output.semanticTable())
}

def produceQueryGraphForPattern(query: String): (QueryGraph, SemanticTable) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ import java.time.Clock

import org.neo4j.cypher.internal.compatibility.v3_3.exceptionHandler
import org.neo4j.cypher.internal.compiler.v3_3.CypherCompilerConfiguration
import org.neo4j.cypher.internal.frontend.{v3_2, v3_3}
import org.neo4j.cypher.internal.frontend.v3_2
import org.neo4j.cypher.internal.frontend.v3_3.InputPosition
import org.neo4j.cypher.internal.frontend.v3_3.helpers.fixedPoint
import org.neo4j.cypher.internal.frontend.v3_3.phases.CompilationPhaseTracer
import org.neo4j.cypher.{InvalidArgumentException, SyntaxException, _}
import org.neo4j.graphdb.factory.GraphDatabaseSettings
import org.neo4j.graphdb.impl.notification.NotificationCode.{CREATE_UNIQUE_UNAVAILABLE_FALLBACK, RULE_PLANNER_UNAVAILABLE_FALLBACK, START_UNAVAILABLE_FALLBACK}
import org.neo4j.graphdb.impl.notification.NotificationCode.{CREATE_UNIQUE_UNAVAILABLE_FALLBACK, RULE_PLANNER_UNAVAILABLE_FALLBACK, START_DEPRECATED, START_UNAVAILABLE_FALLBACK}
import org.neo4j.graphdb.impl.notification.NotificationDetail.Factory.startDeprecated
import org.neo4j.kernel.GraphDatabaseQueryService
import org.neo4j.kernel.api.KernelAPI
import org.neo4j.kernel.configuration.Config
Expand Down Expand Up @@ -164,12 +165,14 @@ class CompilerEngineDelegator(graph: GraphDatabaseQueryService,

parserQuery.onError {
// if there is a create unique in the cypher 3.3 query try to fallback to 3.1
case ex: v3_3.SyntaxException if ex.getMessage.startsWith("CREATE UNIQUE") =>
case ex: frontend.v3_3.SyntaxException if ex.getMessage.startsWith("CREATE UNIQUE") =>
preParsingNotifications = preParsingNotifications +
createUniqueNotifiction(ex, preParsedQuery)
createUniqueNotification(ex, preParsedQuery)
Left(CypherVersion.v3_1)
case ex: v3_3.SyntaxException if ex.getMessage.startsWith("START is no longer supported") =>
preParsingNotifications = preParsingNotifications + createStartNotifiction(ex, preParsedQuery)
case ex: frontend.v3_3.SyntaxException if ex.getMessage.startsWith("START is deprecated") =>
preParsingNotifications = preParsingNotifications +
createStartUnavailableNotification(ex, preParsedQuery) +
createStartDeprecatedNotification(ex, preParsedQuery)
Left(CypherVersion.v3_1)
case _ => Right(parserQuery)
}.getOrElse(Right(parserQuery))
Expand All @@ -181,10 +184,13 @@ class CompilerEngineDelegator(graph: GraphDatabaseQueryService,
parserQuery.onError {
// if there is a create unique in the cypher 3.2 query try to fallback to 3.1
case ex: v3_2.SyntaxException if ex.getMessage.startsWith("CREATE UNIQUE") =>
preParsingNotifications = preParsingNotifications + createUniqueNotifiction(ex, preParsedQuery)
preParsingNotifications = preParsingNotifications + createUniqueNotification(ex, preParsedQuery)
Left(CypherVersion.v3_1)
case ex: v3_2.SyntaxException if ex.getMessage.startsWith("START is no longer supported") =>
preParsingNotifications = preParsingNotifications + createStartNotifiction(ex, preParsedQuery)
preParsingNotifications = preParsingNotifications +
createStartNotification(ex, preParsedQuery) +
createStartDeprecatedNotification(ex, preParsedQuery)

Left(CypherVersion.v3_1)
case _ => Right(parserQuery)
}.getOrElse(Right(parserQuery))
Expand All @@ -206,25 +212,35 @@ class CompilerEngineDelegator(graph: GraphDatabaseQueryService,
result.right.get
}

private def createStartNotifiction(ex: v3_3.SyntaxException, preParsedQuery: PreParsedQuery) = {
private def createStartUnavailableNotification(ex: frontend.v3_3.SyntaxException, preParsedQuery: PreParsedQuery) = {
val pos = convertInputPosition(ex.pos.getOrElse(preParsedQuery.offset))

START_UNAVAILABLE_FALLBACK.notification(pos)
}

private def createStartDeprecatedNotification(ex: frontend.v3_3.SyntaxException, preParsedQuery: PreParsedQuery) = {
val pos = convertInputPosition(ex.pos.getOrElse(preParsedQuery.offset))
START_DEPRECATED.notification(pos, startDeprecated(ex.getMessage))
}

private def createUniqueNotifiction(ex: v3_3.SyntaxException, preParsedQuery: PreParsedQuery) = {
private def createUniqueNotification(ex: frontend.v3_3.SyntaxException, preParsedQuery: PreParsedQuery) = {
val pos = convertInputPosition(ex.pos.getOrElse(preParsedQuery.offset))
CREATE_UNIQUE_UNAVAILABLE_FALLBACK.notification(pos)
}

private def createStartNotifiction(ex: v3_2.SyntaxException, preParsedQuery: PreParsedQuery) = {
private def createStartNotification(ex: v3_2.SyntaxException, preParsedQuery: PreParsedQuery) = {
val pos = convertInputPosition(ex.pos.getOrElse(
v3_2.InputPosition(preParsedQuery.offset.offset, preParsedQuery.offset.line, preParsedQuery.offset.column)))
START_UNAVAILABLE_FALLBACK.notification(pos)
}

private def createStartDeprecatedNotification(ex: frontend.v3_2.SyntaxException, preParsedQuery: PreParsedQuery) = {
val pos = convertInputPosition(ex.pos.getOrElse(
v3_2.InputPosition(preParsedQuery.offset.offset, preParsedQuery.offset.line, preParsedQuery.offset.column)))
START_DEPRECATED.notification(pos, startDeprecated(ex.getMessage))
}

private def createUniqueNotifiction(ex: v3_2.SyntaxException, preParsedQuery: PreParsedQuery) = {
private def createUniqueNotification(ex: v3_2.SyntaxException, preParsedQuery: PreParsedQuery) = {
val pos = convertInputPosition(ex.pos.getOrElse(
v3_2.InputPosition(preParsedQuery.offset.offset, preParsedQuery.offset.line, preParsedQuery.offset.column)))
CREATE_UNIQUE_UNAVAILABLE_FALLBACK.notification(pos)
Expand Down Expand Up @@ -255,7 +271,7 @@ class CompilerEngineDelegator(graph: GraphDatabaseQueryService,
}

private def getMinimumTimeBeforeReplanning: Long = {
val setting: (Config) => Long = config => config.get(GraphDatabaseSettings.cypher_min_replan_interval).toMillis().longValue()
val setting: (Config) => Long = config => config.get(GraphDatabaseSettings.cypher_min_replan_interval).toMillis.longValue()
getSetting(graph, setting, DEFAULT_QUERY_PLAN_TTL)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import org.neo4j.cypher.internal.spi.v3_1.{TransactionalContextWrapper => Transa
import org.neo4j.cypher.internal.spi.v3_3.{TransactionalContextWrapper => TransactionalContextWrapperV3_3}
import org.neo4j.cypher.internal.{frontend, _}
import org.neo4j.kernel.GraphDatabaseQueryService
import org.neo4j.kernel.api.query.{IndexUsage, PlannerInfo}
import org.neo4j.kernel.api.KernelAPI
import org.neo4j.kernel.api.query.{IndexUsage, PlannerInfo}
import org.neo4j.kernel.impl.query.QueryExecutionMonitor
import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors}
import org.neo4j.logging.Log
Expand All @@ -55,7 +55,7 @@ trait Compatibility {

protected val compiler: v3_1.CypherCompiler

implicit val executionMonitor = kernelMonitors.newMonitor(classOf[QueryExecutionMonitor])
implicit val executionMonitor: QueryExecutionMonitor = kernelMonitors.newMonitor(classOf[QueryExecutionMonitor])

def produceParsedQuery(preParsedQuery: PreParsedQuery, tracer: CompilationPhaseTracer,
preParsingNotifications: Set[org.neo4j.graphdb.Notification]): ParsedQuery = {
Expand All @@ -81,7 +81,7 @@ trait Compatibility {
(new ExecutionPlanWrapper(planImpl, preParsingNotifications), extractedParameters)
}

override protected val trier = preparedSyntacticQueryForV_3_1
override protected val trier: Try[PreparedQuerySyntax] = preparedSyntacticQueryForV_3_1
}
}

Expand Down Expand Up @@ -111,7 +111,7 @@ trait Compatibility {
}
}

def isPeriodicCommit = inner.isPeriodicCommit
def isPeriodicCommit: Boolean = inner.isPeriodicCommit

def isStale(lastCommittedTxId: LastCommittedTxIdProvider, ctx: TransactionalContextWrapperV3_3): Boolean =
inner.isStale(lastCommittedTxId, TransactionBoundGraphStatistics(ctx.readOperations))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import org.neo4j.cypher.internal.compiler.v3_2.executionplan.{LegacyNodeIndexUsa
import org.neo4j.cypher.internal.compiler.v3_2.phases.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}
import org.neo4j.cypher.internal.frontend.v3_2.phases.{BaseState, CompilationPhaseTracer, RecordingNotificationLogger}
import org.neo4j.cypher.internal.spi.v3_2.TransactionBoundQueryContext.IndexSearchMonitor
import org.neo4j.cypher.internal.spi.v3_2.{ExceptionTranslatingPlanContext, TransactionBoundGraphStatistics, TransactionBoundPlanContext, TransactionBoundQueryContext, TransactionalContextWrapper => TransactionalContextWrapperV3_2}
import org.neo4j.cypher.internal.spi.v3_3.{TransactionalContextWrapper => TransactionalContextWrapperV3_3}
import org.neo4j.kernel.api.KernelAPI
import org.neo4j.cypher.internal.{frontend, _}
import org.neo4j.kernel.api.KernelAPI
import org.neo4j.kernel.api.query.IndexUsage.{legacyIndexUsage, schemaIndexUsage}
import org.neo4j.kernel.api.query.PlannerInfo
import org.neo4j.kernel.impl.query.QueryExecutionMonitor
Expand Down Expand Up @@ -82,7 +82,7 @@ trait Compatibility[C <: CompilerContext] {
(new ExecutionPlanWrapper(planImpl, preParsingNotifications), extractedParameters)
}

override protected val trier = preparedSyntacticQueryForV_3_2
override protected val trier: Try[BaseState] = preparedSyntacticQueryForV_3_2
}
}

Expand Down Expand Up @@ -113,12 +113,12 @@ trait Compatibility[C <: CompilerContext] {
}
}

def isPeriodicCommit = inner.isPeriodicCommit
def isPeriodicCommit: Boolean = inner.isPeriodicCommit

def isStale(lastCommittedTxId: LastCommittedTxIdProvider, ctx: TransactionalContextWrapperV3_3): Boolean =
inner.isStale(lastCommittedTxId, TransactionBoundGraphStatistics(ctx.readOperations))

override def plannerInfo = {
override def plannerInfo: PlannerInfo = {
import scala.collection.JavaConverters._
new PlannerInfo(inner.plannerUsed.name, inner.runtimeUsed.name, inner.plannedIndexUsage.map {
case SchemaIndexSeekUsage(identifier, label, propertyKeys) => schemaIndexUsage(identifier, label, propertyKeys: _*)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ package org.neo4j.cypher.internal.compatibility.v3_2

import org.neo4j.cypher.InternalException
import org.neo4j.cypher.internal.compiler.v3_2.{CypherCompilerConfiguration => CypherCompilerConfiguration3_2}
import org.neo4j.cypher.internal.frontend.v3_3.phases.CompilationPhaseTracer.{CompilationPhase => v3_3Phase}
import org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.{CompilationPhase => v3_2Phase, CompilationPhaseEvent => CompilationPhaseEvent3_2}
import org.neo4j.cypher.internal.compiler.v3_3.CypherCompilerConfiguration
import org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.{CompilationPhase => v3_2Phase, CompilationPhaseEvent => CompilationPhaseEvent3_2}
import org.neo4j.cypher.internal.frontend.v3_2.{InputPosition => InputPosition3_2}
import org.neo4j.cypher.internal.frontend.v3_3.InputPosition
import org.neo4j.cypher.internal.frontend.v3_3.phases.CompilationPhaseTracer
import org.neo4j.cypher.internal.frontend.v3_3.phases.CompilationPhaseTracer.{CompilationPhase => v3_3Phase}
import org.neo4j.kernel.impl.query.{QueryExecutionMonitor, TransactionalContext}


object helpers {
implicit def monitorFailure(t: Throwable)(implicit monitor: QueryExecutionMonitor, tc: TransactionalContext): Unit = {
monitor.endFailure(tc.executingQuery(), t)
Expand All @@ -50,7 +49,7 @@ object helpers {

def as3_2(tracer: CompilationPhaseTracer): org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer = {
new org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer {
override def beginPhase(phase: org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.CompilationPhase) = {
override def beginPhase(phase: org.neo4j.cypher.internal.frontend.v3_2.phases.CompilationPhaseTracer.CompilationPhase): CompilationPhaseEvent3_2 = {
val wrappedPhase = phase match {
case v3_2Phase.AST_REWRITE => v3_3Phase.AST_REWRITE
case v3_2Phase.CODE_GENERATION => v3_3Phase.CODE_GENERATION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ import java.time.Clock
import org.neo4j.cypher.internal._
import org.neo4j.cypher.internal.compatibility._
import org.neo4j.cypher.internal.compatibility.v3_3.runtime._
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.executionplan.{PlanFingerprint, PlanFingerprintReference, ExecutionPlan => ExecutionPlan_v3_3}
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.executionplan.procs.ProcedureCallOrSchemaCommandExecutionPlanBuilder
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.executionplan.{ExecutionPlan => ExecutionPlan_v3_3}
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.helpers.simpleExpressionEvaluator
import org.neo4j.cypher.internal.compatibility.v3_3.runtime.phases.CompilationState
import org.neo4j.cypher.internal.compiler.v3_3
import org.neo4j.cypher.internal.compiler.v3_3.phases.{CompilationContains, CompilerContext, LogicalPlanState}
import org.neo4j.cypher.internal.compiler.v3_3._
import org.neo4j.cypher.internal.compiler.v3_3.phases.{CompilationContains, LogicalPlanState}
import org.neo4j.cypher.internal.compiler.v3_3.planner.logical.idp._
import org.neo4j.cypher.internal.compiler.v3_3.planner.logical.plans.{LegacyNodeIndexUsage, LegacyRelationshipIndexUsage, SchemaIndexScanUsage, SchemaIndexSeekUsage}
import org.neo4j.cypher.internal.compiler.v3_3.planner.logical.{CachedMetricsFactory, QueryGraphSolver, SimpleMetricsFactory}
import org.neo4j.cypher.internal.compiler.v3_3.spi.PlanContext
import org.neo4j.cypher.internal.compiler.v3_3._
import org.neo4j.cypher.internal.compiler.v3_3.planner.logical.plans.{LegacyNodeIndexUsage, LegacyRelationshipIndexUsage, SchemaIndexScanUsage, SchemaIndexSeekUsage}
import org.neo4j.cypher.internal.frontend.v3_3.ast.Statement
import org.neo4j.cypher.internal.frontend.v3_3.helpers.rewriting.RewriterStepSequencer
import org.neo4j.cypher.internal.frontend.v3_3.phases._
Expand Down Expand Up @@ -181,12 +181,12 @@ trait Compatibility[CONTEXT <: CommunityRuntimeContext,
}
}

def isPeriodicCommit = inner.isPeriodicCommit
def isPeriodicCommit: Boolean = inner.isPeriodicCommit

def isStale(lastCommittedTxId: LastCommittedTxIdProvider, ctx: TransactionalContextWrapper): Boolean =
inner.isStale(lastCommittedTxId, TransactionBoundGraphStatistics(ctx.readOperations))

override def plannerInfo = {
override def plannerInfo: PlannerInfo = {
new PlannerInfo(inner.plannerUsed.name, inner.runtimeUsed.name, inner.plannedIndexUsage.map {
case SchemaIndexSeekUsage(identifier, label, propertyKeys) => schemaIndexUsage(identifier, label, propertyKeys: _*)
case SchemaIndexScanUsage(identifier, label, propertyKey) => schemaIndexUsage(identifier, label, propertyKey)
Expand Down

0 comments on commit 7ca2954

Please sign in to comment.