From 9b8fd85dee1f8c3604a4fac434bd3c16d36fca75 Mon Sep 17 00:00:00 2001 From: Christofer Dutz Date: Sat, 7 Nov 2026 15:26:54 +0100 Subject: [PATCH] [Parser] Skip error recovery in the SLL stage of the tree and table SQL parsers Both parsers try the faster SLL prediction mode first and fall back to LL on a syntax error; the LL stage reports the error. The SLL stage still used the default (tree) or reporting (table) error strategy, which runs sync() at every rule and attempts recovery that is thrown away anyway. It now uses BailErrorStrategy; the table parser switches back to its reporting strategy before the LL stage and also catches the ParseCancellationException of the bail. Parse results and error messages are unchanged. Measured with SQL inserts on a standalone node: tree model +6.4 % throughput (server CPU -6.3 % per value), table model +16.3 % (CPU -13.5 % per value). --- .../queryengine/plan/parser/StatementGenerator.java | 4 ++++ .../plan/relational/sql/parser/SqlParser.java | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java index 7464e6d99fbfc..046a94c1fa243 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java @@ -94,6 +94,7 @@ import org.apache.iotdb.service.rpc.thrift.TSSetSchemaTemplateReq; import org.apache.iotdb.service.rpc.thrift.TSUnsetSchemaTemplateReq; +import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; @@ -857,6 +858,9 @@ private static Statement invokeParser(String sql, ZoneId zoneId) { IoTDBSqlParser parser1 = new IoTDBSqlParser(tokens1); parser1.getInterpreter().setPredictionMode(PredictionMode.SLL); + // Any error in this stage falls back to the LL stage below, which reports it, so + // the SLL stage needs no recovery; BailErrorStrategy also skips the per-rule sync() checks. + parser1.setErrorHandler(new BailErrorStrategy()); parser1.removeErrorListeners(); parser1.addErrorListener(SqlParseError.INSTANCE); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java index 3f741e635e453..809665c0ef037 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java @@ -34,6 +34,7 @@ import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlParser; import org.antlr.v4.runtime.ANTLRErrorListener; +import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonToken; @@ -47,6 +48,7 @@ import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.atn.PredictionMode; import org.antlr.v4.runtime.misc.Pair; +import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.tree.TerminalNode; import java.time.ZoneId; @@ -158,7 +160,7 @@ private Node invokeParser( // Override the default error strategy to not attempt inserting or deleting a token. // Otherwise, it messes up error reporting - parser.setErrorHandler( + DefaultErrorStrategy reportingErrorStrategy = new DefaultErrorStrategy() { @Override public Token recoverInline(Parser recognizer) throws RecognitionException { @@ -167,7 +169,11 @@ public Token recoverInline(Parser recognizer) throws RecognitionException { } throw new InputMismatchException(recognizer, nextTokensState, nextTokensContext); } - }); + }; + // Any error in the SLL stage falls back to the LL stage, which reports it with the strategy + // above, so the SLL stage needs no recovery; BailErrorStrategy also skips the per-rule sync() + // checks. + parser.setErrorHandler(new BailErrorStrategy()); parser.addParseListener(new PostProcessor(Arrays.asList(parser.getRuleNames()), parser)); @@ -183,10 +189,11 @@ public Token recoverInline(Parser recognizer) throws RecognitionException { // first, try parsing with potentially faster SLL mode parser.getInterpreter().setPredictionMode(PredictionMode.SLL); tree = parseFunction.apply(parser); - } catch (ParsingException ex) { + } catch (ParsingException | ParseCancellationException ex) { // if we fail, parse with LL mode tokenStream.seek(0); // rewind input stream parser.reset(); + parser.setErrorHandler(reportingErrorStrategy); parser.getInterpreter().setPredictionMode(PredictionMode.LL); tree = parseFunction.apply(parser);