From 307a60ce8a3139389376404a01a030e4c9cfa4ca Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 16:06:09 +0200 Subject: [PATCH 1/7] avoid instanceof in catch --- .../xpack/esql/session/EsqlSession.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 307be48de1a9e..42c9f4575b826 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -755,27 +755,25 @@ private static void analyzeAndMaybeRetry( EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, requestFilter != null); } plan = analyzeAction.apply(result); - } catch (Exception e) { - if (e instanceof VerificationException ve) { - LOGGER.debug( - "Analyzing the plan ({} attempt, {} filter) failed with {}", - attemptMessage, - filterPresentMessage, - ve.getDetailedMessage() - ); - if (requestFilter == null) { - // if the initial request didn't have a filter, then just pass the exception back to the user - logicalPlanListener.onFailure(ve); - } else { - // interested only in a VerificationException, but this time we are taking out the index filter - // to try and make the index resolution work without any index filtering. In the next step... to be continued - l.onResponse(result); - } + } catch (VerificationException ve) { + LOGGER.debug( + "Analyzing the plan ({} attempt, {} filter) failed with {}", + attemptMessage, + filterPresentMessage, + ve.getDetailedMessage() + ); + if (requestFilter == null) { + // if the initial request didn't have a filter, then just pass the exception back to the user + logicalPlanListener.onFailure(ve); } else { - // if the query failed with any other type of exception, then just pass the exception back to the user - logicalPlanListener.onFailure(e); + // interested only in a VerificationException, but this time we are taking out the index filter + // to try and make the index resolution work without any index filtering. In the next step... to be continued + l.onResponse(result); } return; + } catch (Exception e) { + logicalPlanListener.onFailure(e); + return; } LOGGER.debug("Analyzed plan ({} attempt, {} filter):\n{}", attemptMessage, filterPresentMessage, plan); // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning From dd7be661af4674af773bdffeca15ba634e701f7d Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 16:09:44 +0200 Subject: [PATCH 2/7] simplify logging description --- .../xpack/esql/session/EsqlSession.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 42c9f4575b826..16c3094586f98 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -441,7 +441,7 @@ public void analyzedPlan( l.onFailure(e); return; } - LOGGER.debug("Analyzed plan (second attempt, without filter):\n{}", plan); + LOGGER.debug("Analyzed plan (second attempt without filter):\n{}", plan); l.onResponse(plan); }).addListener(logicalPlanListener); } @@ -744,9 +744,9 @@ private static void analyzeAndMaybeRetry( ActionListener l ) { LogicalPlan plan = null; - var filterPresentMessage = requestFilter == null ? "without" : "with"; - var attemptMessage = requestFilter == null ? "the only" : "first"; - LOGGER.debug("Analyzing the plan ({} attempt, {} filter)", attemptMessage, filterPresentMessage); + + var description = requestFilter == null ? "the only attempt without filter" : "first attempt with filter"; + LOGGER.debug("Analyzing the plan ({})", description); try { if (result.indices.isValid() || requestFilter != null) { @@ -756,12 +756,7 @@ private static void analyzeAndMaybeRetry( } plan = analyzeAction.apply(result); } catch (VerificationException ve) { - LOGGER.debug( - "Analyzing the plan ({} attempt, {} filter) failed with {}", - attemptMessage, - filterPresentMessage, - ve.getDetailedMessage() - ); + LOGGER.debug("Analyzing the plan ({}) failed with {}", description, ve.getDetailedMessage()); if (requestFilter == null) { // if the initial request didn't have a filter, then just pass the exception back to the user logicalPlanListener.onFailure(ve); @@ -775,7 +770,7 @@ private static void analyzeAndMaybeRetry( logicalPlanListener.onFailure(e); return; } - LOGGER.debug("Analyzed plan ({} attempt, {} filter):\n{}", attemptMessage, filterPresentMessage, plan); + LOGGER.debug("Analyzed plan ({}):\n{}", description, plan); // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning logicalPlanListener.onResponse(plan); } From e3b4248949a2b1f2c51346551445dccef739ef12 Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 16:46:41 +0200 Subject: [PATCH 3/7] avoid unnecessary returns --- .../xpack/esql/session/EsqlSession.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 16c3094586f98..85586b6423636 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -741,10 +741,8 @@ private static void analyzeAndMaybeRetry( PreAnalysisResult result, EsqlExecutionInfo executionInfo, ActionListener logicalPlanListener, - ActionListener l + ActionListener stepListener ) { - LogicalPlan plan = null; - var description = requestFilter == null ? "the only attempt without filter" : "first attempt with filter"; LOGGER.debug("Analyzing the plan ({})", description); @@ -754,25 +752,22 @@ private static void analyzeAndMaybeRetry( // when the resolution result is not valid for a different reason. EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, requestFilter != null); } - plan = analyzeAction.apply(result); + LogicalPlan plan = analyzeAction.apply(result); + LOGGER.debug("Analyzed plan ({}):\n{}", description, plan); + // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning + logicalPlanListener.onResponse(plan); } catch (VerificationException ve) { LOGGER.debug("Analyzing the plan ({}) failed with {}", description, ve.getDetailedMessage()); if (requestFilter == null) { // if the initial request didn't have a filter, then just pass the exception back to the user logicalPlanListener.onFailure(ve); } else { - // interested only in a VerificationException, but this time we are taking out the index filter - // to try and make the index resolution work without any index filtering. In the next step... to be continued - l.onResponse(result); + // retrying and make the index resolution work without any index filtering. + stepListener.onResponse(result); } - return; } catch (Exception e) { logicalPlanListener.onFailure(e); - return; } - LOGGER.debug("Analyzed plan ({}):\n{}", description, plan); - // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning - logicalPlanListener.onResponse(plan); } private void resolveInferences(LogicalPlan plan, PreAnalysisResult preAnalysisResult, ActionListener l) { From 49b47c911d5038061b4a3160d609c23a06070714 Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 16:47:13 +0200 Subject: [PATCH 4/7] rename method --- .../org/elasticsearch/xpack/esql/session/EsqlSession.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 85586b6423636..8c81c69f767a2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -421,7 +421,7 @@ public void analyzedPlan( l.onResponse(result); }).andThen((l, result) -> { // first attempt (maybe the only one) at analyzing the plan - analyzeAndMaybeRetry(analyzeAction, requestFilter, result, executionInfo, logicalPlanListener, l); + analyzeWithRetry(analyzeAction, requestFilter, result, executionInfo, logicalPlanListener, l); }).andThen((l, result) -> { assert requestFilter != null : "The second pre-analysis shouldn't take place when there is no index filter in the request"; @@ -735,7 +735,7 @@ private boolean allCCSClustersSkipped( return false; } - private static void analyzeAndMaybeRetry( + private static void analyzeWithRetry( CheckedFunction analyzeAction, QueryBuilder requestFilter, PreAnalysisResult result, From 371f2e4109b07ffe1e7f378b35d65d6c1b2b4e79 Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 17:20:46 +0200 Subject: [PATCH 5/7] inline allCCSClustersSkipped --- .../xpack/esql/session/EsqlSession.java | 43 ++++++------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 8c81c69f767a2..2e63fadfae107 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -412,13 +412,6 @@ public void analyzedPlan( listener.andThen((l, result) -> { // resolve the main indices preAnalyzeMainIndices(preAnalysis, executionInfo, result, requestFilter, l); - }).andThen((l, result) -> { - // TODO in follow-PR (for skip_unavailable handling of missing concrete indexes) add some tests for - // invalid index resolution to updateExecutionInfo - // If we run out of clusters to search due to unavailability we can stop the analysis right here - if (result.indices.isValid() && allCCSClustersSkipped(executionInfo, result, logicalPlanListener)) return; - // whatever tuple we have here (from CCS-special handling or from the original pre-analysis), pass it on to the next step - l.onResponse(result); }).andThen((l, result) -> { // first attempt (maybe the only one) at analyzing the plan analyzeWithRetry(analyzeAction, requestFilter, result, executionInfo, logicalPlanListener, l); @@ -711,30 +704,6 @@ private void preAnalyzeMainIndices( } } - /** - * Check if there are any clusters to search. - * - * @return true if there are no clusters to search, false otherwise - */ - private boolean allCCSClustersSkipped( - EsqlExecutionInfo executionInfo, - PreAnalysisResult result, - ActionListener logicalPlanListener - ) { - IndexResolution indexResolution = result.indices; - EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, indexResolution.failures()); - if (executionInfo.isCrossClusterSearch() - && executionInfo.getClusterStates(EsqlExecutionInfo.Cluster.Status.RUNNING).findAny().isEmpty()) { - // for a CCS, if all clusters have been marked as SKIPPED, nothing to search so send a sentinel Exception - // to let the LogicalPlanActionListener decide how to proceed - LOGGER.debug("No more clusters to search, ending analysis stage"); - logicalPlanListener.onFailure(new NoClustersToSearchException()); - return true; - } - - return false; - } - private static void analyzeWithRetry( CheckedFunction analyzeAction, QueryBuilder requestFilter, @@ -743,6 +712,18 @@ private static void analyzeWithRetry( ActionListener logicalPlanListener, ActionListener stepListener ) { + if (result.indices.isValid()) { + EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, result.indices.failures()); + if (executionInfo.isCrossClusterSearch() + && executionInfo.getClusterStates(EsqlExecutionInfo.Cluster.Status.RUNNING).findAny().isEmpty()) { + // for a CCS, if all clusters have been marked as SKIPPED, nothing to search so send a sentinel Exception + // to let the LogicalPlanActionListener decide how to proceed + LOGGER.debug("No more clusters to search, ending analysis stage"); + logicalPlanListener.onFailure(new NoClustersToSearchException()); + return; + } + } + var description = requestFilter == null ? "the only attempt without filter" : "first attempt with filter"; LOGGER.debug("Analyzing the plan ({})", description); From 237805a1308377fd0588df1f55d5fdbe414641c9 Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 17:39:20 +0200 Subject: [PATCH 6/7] inline trailing steps --- .../xpack/esql/session/EsqlSession.java | 62 ++++++++----------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 2e63fadfae107..4b5e6919432e5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -409,34 +409,9 @@ public void analyzedPlan( for (var index : preAnalysis.lookupIndices) { listener = listener.andThen((l, preAnalysisResult) -> preAnalyzeLookupIndex(index, preAnalysisResult, executionInfo, l)); } - listener.andThen((l, result) -> { - // resolve the main indices - preAnalyzeMainIndices(preAnalysis, executionInfo, result, requestFilter, l); - }).andThen((l, result) -> { - // first attempt (maybe the only one) at analyzing the plan - analyzeWithRetry(analyzeAction, requestFilter, result, executionInfo, logicalPlanListener, l); - }).andThen((l, result) -> { - assert requestFilter != null : "The second pre-analysis shouldn't take place when there is no index filter in the request"; - - // here the requestFilter is set to null, performing the pre-analysis after the first step failed - preAnalyzeMainIndices(preAnalysis, executionInfo, result, null, l); - }).andThen((l, result) -> { - assert requestFilter != null : "The second analysis shouldn't take place when there is no index filter in the request"; - LOGGER.debug("Analyzing the plan (second attempt, without filter)"); - LogicalPlan plan; - try { - // the order here is tricky - if the cluster has been filtered and later became unavailable, - // do we want to declare it successful or skipped? For now, unavailability takes precedence. - EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, result.indices.failures()); - EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, false); - plan = analyzeAction.apply(result); - } catch (Exception e) { - l.onFailure(e); - return; - } - LOGGER.debug("Analyzed plan (second attempt without filter):\n{}", plan); - l.onResponse(plan); - }).addListener(logicalPlanListener); + listener.andThen((l, result) -> preAnalyzeMainIndices(preAnalysis, executionInfo, result, requestFilter, l)) + .andThen((l, result) -> analyzeWithRetry(analyzeAction, requestFilter, preAnalysis, executionInfo, result, l)) + .addListener(logicalPlanListener); } private void preAnalyzeLookupIndex( @@ -704,13 +679,13 @@ private void preAnalyzeMainIndices( } } - private static void analyzeWithRetry( + private void analyzeWithRetry( CheckedFunction analyzeAction, QueryBuilder requestFilter, - PreAnalysisResult result, + PreAnalyzer.PreAnalysis preAnalysis, EsqlExecutionInfo executionInfo, - ActionListener logicalPlanListener, - ActionListener stepListener + PreAnalysisResult result, + ActionListener listener ) { if (result.indices.isValid()) { EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, result.indices.failures()); @@ -719,7 +694,7 @@ private static void analyzeWithRetry( // for a CCS, if all clusters have been marked as SKIPPED, nothing to search so send a sentinel Exception // to let the LogicalPlanActionListener decide how to proceed LOGGER.debug("No more clusters to search, ending analysis stage"); - logicalPlanListener.onFailure(new NoClustersToSearchException()); + listener.onFailure(new NoClustersToSearchException()); return; } } @@ -736,18 +711,31 @@ private static void analyzeWithRetry( LogicalPlan plan = analyzeAction.apply(result); LOGGER.debug("Analyzed plan ({}):\n{}", description, plan); // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning - logicalPlanListener.onResponse(plan); + listener.onResponse(plan); } catch (VerificationException ve) { LOGGER.debug("Analyzing the plan ({}) failed with {}", description, ve.getDetailedMessage()); if (requestFilter == null) { // if the initial request didn't have a filter, then just pass the exception back to the user - logicalPlanListener.onFailure(ve); + listener.onFailure(ve); } else { // retrying and make the index resolution work without any index filtering. - stepListener.onResponse(result); + preAnalyzeMainIndices(preAnalysis, executionInfo, result, null, listener.delegateFailure((l, r) -> { + LOGGER.debug("Analyzing the plan (second attempt, without filter)"); + try { + // the order here is tricky - if the cluster has been filtered and later became unavailable, + // do we want to declare it successful or skipped? For now, unavailability takes precedence. + EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, r.indices.failures()); + EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, r.indices, false); + LogicalPlan plan = analyzeAction.apply(r); + LOGGER.debug("Analyzed plan (second attempt without filter):\n{}", plan); + l.onResponse(plan); + } catch (Exception e) { + l.onFailure(e); + } + })); } } catch (Exception e) { - logicalPlanListener.onFailure(e); + listener.onFailure(e); } } From 0bed3de9f483d3cd8ed68b1f0cb440b95f0a50ce Mon Sep 17 00:00:00 2001 From: "ievgen.degtiarenko" Date: Wed, 13 Aug 2025 17:46:14 +0200 Subject: [PATCH 7/7] replace analyzeAction with a method --- .../xpack/esql/session/EsqlSession.java | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 4b5e6919432e5..e34777ee10b13 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -20,7 +20,6 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverCompletionInfo; import org.elasticsearch.compute.operator.FailureCollector; -import org.elasticsearch.core.CheckedFunction; import org.elasticsearch.core.Releasables; import org.elasticsearch.index.IndexMode; import org.elasticsearch.index.mapper.IndexModeFieldMapper; @@ -384,25 +383,13 @@ public void analyzedPlan( return; } - CheckedFunction analyzeAction = (l) -> { - handleFieldCapsFailures(configuration.allowPartialResults(), executionInfo, l.indices.failures()); - Analyzer analyzer = new Analyzer( - new AnalyzerContext(configuration, functionRegistry, l.indices, l.lookupIndices, l.enrichResolution, l.inferenceResolution), - verifier - ); - LogicalPlan plan = analyzer.analyze(parsed); - plan.setAnalyzed(); - return plan; - }; - PreAnalyzer.PreAnalysis preAnalysis = preAnalyzer.preAnalyze(parsed); var unresolvedPolicies = preAnalysis.enriches.stream().map(EnrichPolicyResolver.UnresolvedPolicy::from).collect(toSet()); EsqlCCSUtils.initCrossClusterState(indicesExpressionGrouper, verifier.licenseState(), preAnalysis.indices, executionInfo); - var listener = SubscribableListener.newForked( - l -> enrichPolicyResolver.resolvePolicies(unresolvedPolicies, executionInfo, l) - ) + var listener = SubscribableListener. // + newForked(l -> enrichPolicyResolver.resolvePolicies(unresolvedPolicies, executionInfo, l)) .andThenApply(enrichResolution -> FieldNameUtils.resolveFieldNames(parsed, enrichResolution)) .andThen((l, preAnalysisResult) -> resolveInferences(parsed, preAnalysisResult, l)); // first resolve the lookup indices, then the main indices @@ -410,7 +397,7 @@ public void analyzedPlan( listener = listener.andThen((l, preAnalysisResult) -> preAnalyzeLookupIndex(index, preAnalysisResult, executionInfo, l)); } listener.andThen((l, result) -> preAnalyzeMainIndices(preAnalysis, executionInfo, result, requestFilter, l)) - .andThen((l, result) -> analyzeWithRetry(analyzeAction, requestFilter, preAnalysis, executionInfo, result, l)) + .andThen((l, result) -> analyzeWithRetry(parsed, requestFilter, preAnalysis, executionInfo, result, l)) .addListener(logicalPlanListener); } @@ -680,7 +667,7 @@ private void preAnalyzeMainIndices( } private void analyzeWithRetry( - CheckedFunction analyzeAction, + LogicalPlan parsed, QueryBuilder requestFilter, PreAnalyzer.PreAnalysis preAnalysis, EsqlExecutionInfo executionInfo, @@ -708,7 +695,7 @@ private void analyzeWithRetry( // when the resolution result is not valid for a different reason. EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, requestFilter != null); } - LogicalPlan plan = analyzeAction.apply(result); + LogicalPlan plan = analyzedPlan(parsed, result, executionInfo); LOGGER.debug("Analyzed plan ({}):\n{}", description, plan); // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning listener.onResponse(plan); @@ -726,7 +713,7 @@ private void analyzeWithRetry( // do we want to declare it successful or skipped? For now, unavailability takes precedence. EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, r.indices.failures()); EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, r.indices, false); - LogicalPlan plan = analyzeAction.apply(r); + LogicalPlan plan = analyzedPlan(parsed, r, executionInfo); LOGGER.debug("Analyzed plan (second attempt without filter):\n{}", plan); l.onResponse(plan); } catch (Exception e) { @@ -761,6 +748,17 @@ private PhysicalPlan logicalPlanToPhysicalPlan(LogicalPlan optimizedPlan, EsqlQu return EstimatesRowSize.estimateRowSize(0, physicalPlan); } + private LogicalPlan analyzedPlan(LogicalPlan parsed, PreAnalysisResult r, EsqlExecutionInfo executionInfo) throws Exception { + handleFieldCapsFailures(configuration.allowPartialResults(), executionInfo, r.indices.failures()); + Analyzer analyzer = new Analyzer( + new AnalyzerContext(configuration, functionRegistry, r.indices, r.lookupIndices, r.enrichResolution, r.inferenceResolution), + verifier + ); + LogicalPlan plan = analyzer.analyze(parsed); + plan.setAnalyzed(); + return plan; + } + private LogicalPlan optimizedPlan(LogicalPlan logicalPlan) { if (logicalPlan.preOptimized() == false) { throw new IllegalStateException("Expected pre-optimized plan");