[jOOQ/jOOQ#11250] Add ParseContext.languageContext()

This includes:

- [jOOQ/jOOQ#10243] Added nullability annotations to ParseContext
- [jOOQ/jOOQ#10243] Document exceptions thrown from ParseContext
This commit is contained in:
Lukas Eder 2021-06-24 09:34:47 +02:00
parent 2d128da1eb
commit 141a3cf0bb
2 changed files with 112 additions and 29 deletions

View File

@ -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.
* <p>
*
*
* @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 <code>"order by"</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 {
* <code>null</code> 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 {
* <code>null</code> 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
<T> List<T> parseList(String separator, Function<? super ParseContext, ? extends T> element);
/**
* Convenience method to parse a list of at least 1 elements.
*/
<T> List<T> parseList(Predicate<? super ParseContext> separator, Function<? super ParseContext, ? extends T> element);
@NotNull
<T> List<T> parseList(Predicate<? super ParseContext> separator,
Function<? super ParseContext, ? extends T> 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);
}

View File

@ -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<Statement> statements = new ArrayList<>();
LanguageContext previous = languageContext;
try {
if (languageContext == LanguageContext.QUERY)
languageContext = LanguageContext.BLOCK;
List<Statement> 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<Name, Field<?>> fieldScope = new ScopeStack<>(null);
private final ScopeStack<Name, FieldProxy<?>> 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;