diff --git a/jOOQ/src/main/java/org/jooq/ParseContext.java b/jOOQ/src/main/java/org/jooq/ParseContext.java index eef5090aa4..a6b5a8e52d 100644 --- a/jOOQ/src/main/java/org/jooq/ParseContext.java +++ b/jOOQ/src/main/java/org/jooq/ParseContext.java @@ -44,11 +44,12 @@ import java.util.function.Predicate; import org.jooq.conf.Settings; import org.jooq.impl.ParserException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + /** * A publicly available API for the internal parse context that allows for * parsing SQL fragements. - *

- * * * @author Lukas Eder */ @@ -61,17 +62,25 @@ public interface ParseContext extends Scope { /** * Convenient access to {@link Settings#getParseDialect()}. */ + @NotNull SQLDialect parseDialect(); /** * Convenient access to {@link Settings#getParseDialect()}'s family. */ + @NotNull SQLDialect parseFamily(); // ------------------------------------------------------------------------- // Parse context // ------------------------------------------------------------------------- + /** + * The current language context. + */ + @NotNull + LanguageContext languageContext(); + /** * The character at the current {@link #position()}. */ @@ -135,6 +144,7 @@ public interface ParseContext extends Scope { * Parse a single character or fail if it cannot be parsed. * * @return Always returns true. + * @throws ParserException if the character could not be parsed. */ boolean parse(char c) throws ParserException; @@ -149,6 +159,7 @@ public interface ParseContext extends Scope { * Parse a string or fail if it cannot be parsed. * * @return Always returns true. + * @throws ParserException if the string could not be parsed. */ boolean parse(String string) throws ParserException; @@ -168,7 +179,7 @@ public interface ParseContext extends Scope { * then "order by" will be parsed as well. * * @return Always returns true. - * @see #parseKeywordIf(String) + * @throws ParserException if the keyword could not be parsed. */ boolean parseKeyword(String keyword) throws ParserException; @@ -188,7 +199,6 @@ public interface ParseContext extends Scope { * Try parsing any keyword. * * @return Whether any of the keywords could be parsed. - * @see #parseKeywordIf(String) */ boolean parseKeywordIf(String... keywords); @@ -196,7 +206,7 @@ public interface ParseContext extends Scope { * Parse any keyword or fail if none of the keywords could be parsed. * * @return Always returns true. - * @see #parseKeyword(String) + * @throws ParserException if none of the keywords could be parsed. */ boolean parseKeyword(String... keywords) throws ParserException; @@ -205,17 +215,18 @@ public interface ParseContext extends Scope { * identifier. * * @return The parsed identifier. - * @see #parseName() + * @throws ParserException if no identifier could be parsed. */ - Name parseIdentifier(); + @NotNull + Name parseIdentifier() throws ParserException; /** * Try parsing an (unqualified) identifier. * * @return The identifier if it could be parsed, or null if the * current token is not an identifier. - * @see #parseNameIf() */ + @Nullable Name parseIdentifierIf(); /** @@ -223,8 +234,9 @@ public interface ParseContext extends Scope { * a name. * * @return The parsed name. - * @see #parseIdentifier() + * @throws ParserException if no name could be parsed. */ + @NotNull Name parseName() throws ParserException; /** @@ -232,8 +244,8 @@ public interface ParseContext extends Scope { * * @return The name if it could be parsed, or null if the * current token is not a name. - * @see #parseIdentifierIf() */ + @Nullable Name parseNameIf(); /** @@ -247,7 +259,6 @@ public interface ParseContext extends Scope { * Try parsing any function name. * * @return Whether any function name could be parsed. - * @see #parseFunctionNameIf(String) */ boolean parseFunctionNameIf(String... names); @@ -256,7 +267,9 @@ public interface ParseContext extends Scope { * literal. * * @return The parsed string literal. + * @throws ParserException if no string literal could be parsed. */ + @NotNull String parseStringLiteral() throws ParserException; /** @@ -265,6 +278,7 @@ public interface ParseContext extends Scope { * @return The string literal if it could be parsed, or null if * the current token is not a string literal. */ + @Nullable String parseStringLiteralIf(); /** @@ -272,8 +286,10 @@ public interface ParseContext extends Scope { * unsigned integer literal. * * @return The unsigned integer literal. + * @throws ParserException if no unsigned integer literal could be parsed. */ - Long parseUnsignedIntegerLiteral(); + @NotNull + Long parseUnsignedIntegerLiteral() throws ParserException; /** * Try parsing an unsigned integer literal. @@ -282,6 +298,7 @@ public interface ParseContext extends Scope { * null if the current token is not an unsigned integer * literal. */ + @Nullable Long parseUnsignedIntegerLiteralIf(); /** @@ -289,8 +306,10 @@ public interface ParseContext extends Scope { * signed integer literal. * * @return The signed integer literal. + * @throws ParserException if no signed integer literal could be parsed. */ - Long parseSignedIntegerLiteral(); + @NotNull + Long parseSignedIntegerLiteral() throws ParserException; /** * Try parsing an signed integer literal. @@ -299,6 +318,7 @@ public interface ParseContext extends Scope { * null if the current token is not an signed integer * literal. */ + @Nullable Long parseSignedIntegerLiteralIf(); /** @@ -306,15 +326,19 @@ public interface ParseContext extends Scope { * not a data type. * * @return The data type. + * @throws ParserException if no data type expression could be parsed. */ - DataType parseDataType(); + @NotNull + DataType parseDataType() throws ParserException; /** * Parse a {@link Field} expression or fail if the current expression is not * a field. * * @return The parsed field. + * @throws ParserException if no field expression could be parsed. */ + @NotNull Field parseField() throws ParserException; /** @@ -322,7 +346,9 @@ public interface ParseContext extends Scope { * not a sort field. * * @return The parsed sort field. + * @throws ParserException if no sort field expression could be parsed. */ + @NotNull SortField parseSortField() throws ParserException; /** @@ -330,7 +356,9 @@ public interface ParseContext extends Scope { * not a condition. * * @return The parsed condition. + * @throws ParserException if no condition expression could be parsed. */ + @NotNull Condition parseCondition() throws ParserException; /** @@ -338,18 +366,23 @@ public interface ParseContext extends Scope { * a table. * * @return The parsed table. + * @throws ParserException if no table expression could be parsed. */ + @NotNull Table parseTable() throws ParserException; /** * Convenience method to parse a list of at least 1 elements. */ + @NotNull List parseList(String separator, Function element); /** * Convenience method to parse a list of at least 1 elements. */ - List parseList(Predicate separator, Function element); + @NotNull + List parseList(Predicate separator, + Function element); /** * Convenience method to parse parenthesised content. @@ -369,7 +402,7 @@ public interface ParseContext extends Scope { /** * An exception that can be thrown from the current position. */ + @NotNull ParserException exception(String message); } - diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index f57aa493fa..6f8049af01 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -234,10 +234,10 @@ import org.jooq.JSONValueOnStep; import org.jooq.JoinType; import org.jooq.Keyword; // ... +import org.jooq.LanguageContext; import org.jooq.LikeEscapeStep; // ... import org.jooq.Merge; -import org.jooq.MergeFinalStep; import org.jooq.MergeMatchedDeleteStep; import org.jooq.MergeMatchedStep; import org.jooq.MergeMatchedWhereStep; @@ -674,7 +674,11 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { scopeStart(); boolean previousMetaLookupsForceIgnore = metaLookupsForceIgnore(); Query result = null; + LanguageContext previous = languageContext; + try { + languageContext = LanguageContext.QUERY; + switch (characterUpper()) { case 'A': if (!parseResultQuery && peekKeyword("ALTER")) @@ -683,8 +687,10 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { break; case 'B': - if (!parseResultQuery && peekKeyword("BEGIN")) + if (!parseResultQuery && peekKeyword("BEGIN")) { + languageContext = previous; return result = parseBlock(false); + } break; @@ -847,6 +853,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { scopeEnd(result); scopeResolve(); metaLookupsForceIgnore(previousMetaLookupsForceIgnore); + languageContext = previous; } } @@ -2765,34 +2772,44 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { } private final Block parseBlock(boolean allowDeclareSection) { - List statements = new ArrayList<>(); + LanguageContext previous = languageContext; + + try { + if (languageContext == LanguageContext.QUERY) + languageContext = LanguageContext.BLOCK; + + List statements = new ArrayList<>(); - if (allowDeclareSection && parseKeywordIf("DECLARE") && requireProEdition()) + if (allowDeclareSection && parseKeywordIf("DECLARE") && requireProEdition()) - ; - else - parseKeywordIf("EXECUTE BLOCK AS"); + ; + else + parseKeywordIf("EXECUTE BLOCK AS"); - parseKeyword("BEGIN"); - parseKeywordIf("ATOMIC", "NOT ATOMIC"); - statements.addAll(parseStatementsAndPeek("END")); - parseKeyword("END"); + parseKeyword("BEGIN"); + parseKeywordIf("ATOMIC", "NOT ATOMIC"); + statements.addAll(parseStatementsAndPeek("END")); + parseKeyword("END"); - parseIf(';'); + parseIf(';'); - return dsl.begin(statements); + return dsl.begin(statements); + } + finally { + languageContext = previous; + } } private final void parseSemicolonAfterNonBlocks(Statement result) { @@ -5336,6 +5353,33 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -13386,6 +13430,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { private final ScopeStack> fieldScope = new ScopeStack<>(null); private final ScopeStack> lookupFields = new ScopeStack<>(null); private boolean scopeClear = false; + private LanguageContext languageContext = LanguageContext.QUERY; @@ -13433,6 +13478,11 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { return parseDialect().family(); } + @Override + public final LanguageContext languageContext() { + return languageContext; + } + private final ParseWithMetaLookups metaLookups() { if (metaLookupsForceIgnore()) return ParseWithMetaLookups.OFF;