[jOOQ/jOOQ#12538] Add Settings.parseRetainCommentsBetweenQueries

This commit is contained in:
Lukas Eder 2021-10-21 15:40:02 +02:00
parent 6870ca20ba
commit 701b9c3b98
6 changed files with 339 additions and 236 deletions

File diff suppressed because it is too large Load Diff

View File

@ -120,6 +120,8 @@ public final class ParserCLI {
settings.setParseNameCase(a.parseNameCase);
if (a.parseNamedParamPrefix != null)
settings.setParseNamedParamPrefix(a.parseNamedParamPrefix);
if (a.parseRetainCommentsBetweenQueries != null)
settings.setParseRetainCommentsBetweenQueries(a.parseRetainCommentsBetweenQueries);
if (a.parseSetCommands != null)
settings.setParseSetCommands(a.parseSetCommands);
if (a.parseTimestampFormat != null)
@ -254,6 +256,12 @@ public final class ParserCLI {
displayParseNamedParamPrefix(a);
}
else if ("parse-retain-comments-between-queries".equals(flag)) {
if (arg != null)
a.parseRetainCommentsBetweenQueries = Boolean.parseBoolean(arg.toLowerCase());
displayParseRetainCommentsBetweenQueries(a);
}
else if ("parse-set-commands".equals(flag)) {
if (arg != null)
a.parseSetCommands = Boolean.parseBoolean(arg.toLowerCase());
@ -396,6 +404,10 @@ public final class ParserCLI {
System.out.println("Parse named param prefix : " + a.parseNamedParamPrefix);
}
private static void displayParseRetainCommentsBetweenQueries(Args a) {
System.out.println("Retain comments between queries : " + a.parseRetainCommentsBetweenQueries);
}
private static void displayParseSetCommands(Args a) {
System.out.println("Parse set commands : " + a.parseSetCommands);
}
@ -529,6 +541,8 @@ public final class ParserCLI {
result.parseNamedParamPrefix = args[++i];
else if ("--parse-set-commands".equals(args[i]))
result.parseSetCommands = true;
else if ("--parse-retain-comments-between-queries".equals(args[i]))
result.parseRetainCommentsBetweenQueries = true;
else if ("--parse-timestamp-format".equals(args[i]))
result.parseTimestampFormat = args[++i];
else if ("--parse-unknown-functions".equals(args[i]))
@ -601,6 +615,7 @@ public final class ParserCLI {
System.out.println(" --parse-locale <Locale>");
System.out.println(" --parse-name-case <ParseNameCase>");
System.out.println(" --parse-named-param-prefix <String>");
System.out.println(" --parse-retain-comments-between-queries");
System.out.println(" --parse-set-commands");
System.out.println(" --parse-timestamp-format <String>");
System.out.println(" --parse-unknown-functions <ParseUnknownFunctions>");
@ -638,6 +653,7 @@ public final class ParserCLI {
System.out.println(" /parse-locale <Locale>");
System.out.println(" /parse-name-case <ParseNameCase>");
System.out.println(" /parse-named-param-prefix <String>");
System.out.println(" /parse-retain-comments-between-queries <boolean>");
System.out.println(" /parse-set-commands <boolean>");
System.out.println(" /parse-timestamp-format <String>");
System.out.println(" /parse-unknown-functions <ParseUnknownFunctions>");
@ -684,6 +700,7 @@ public final class ParserCLI {
Locale parseLocale = d.getParseLocale();
ParseNameCase parseNameCase = d.getParseNameCase();
String parseNamedParamPrefix = d.getParseNamedParamPrefix();
Boolean parseRetainCommentsBetweenQueries = d.isParseRetainCommentsBetweenQueries();
Boolean parseSetCommands = d.isParseSetCommands();
String parseTimestampFormat = d.getParseTimestampFormat();
ParseUnknownFunctions parseUnknownFunctions = d.getParseUnknownFunctions();

View File

@ -316,6 +316,8 @@ public class Settings
protected String parseIgnoreCommentStart = "[jooq ignore start]";
@XmlElement(defaultValue = "[jooq ignore stop]")
protected String parseIgnoreCommentStop = "[jooq ignore stop]";
@XmlElement(defaultValue = "false")
protected Boolean parseRetainCommentsBetweenQueries = false;
@XmlElement(defaultValue = "true")
protected Boolean parseMetaDefaultExpressions = true;
@XmlElement(defaultValue = "true")
@ -2881,6 +2883,36 @@ public class Settings
this.parseIgnoreCommentStop = value;
}
/**
* [#12538] Whether the parser should retain comments and whitespace between queries when parsing multiple queries through {@link org.jooq.Parser#parse(String)}.
* <p>
* jOOQ's query object model doesn't have a way to represent comments
* or other whitespace, and as such, the parser simply skips them by default.
* However, it may be desirable to retain comments before or in between top
* level queries, when parsing multiple such queries in a script. Comments
* inside of queries (including procedural statements) are still not supported.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isParseRetainCommentsBetweenQueries() {
return parseRetainCommentsBetweenQueries;
}
/**
* Sets the value of the parseRetainCommentsBetweenQueries property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setParseRetainCommentsBetweenQueries(Boolean value) {
this.parseRetainCommentsBetweenQueries = value;
}
/**
* [#8469] Whether to parse default expressions retrieved from {@link java.sql.DatabaseMetaData}.
*
@ -3911,6 +3943,11 @@ public class Settings
return this;
}
public Settings withParseRetainCommentsBetweenQueries(Boolean value) {
setParseRetainCommentsBetweenQueries(value);
return this;
}
public Settings withParseMetaDefaultExpressions(Boolean value) {
setParseMetaDefaultExpressions(value);
return this;
@ -4102,6 +4139,7 @@ public class Settings
builder.append("parseIgnoreComments", parseIgnoreComments);
builder.append("parseIgnoreCommentStart", parseIgnoreCommentStart);
builder.append("parseIgnoreCommentStop", parseIgnoreCommentStop);
builder.append("parseRetainCommentsBetweenQueries", parseRetainCommentsBetweenQueries);
builder.append("parseMetaDefaultExpressions", parseMetaDefaultExpressions);
builder.append("applyWorkaroundFor7962", applyWorkaroundFor7962);
builder.append("interpreterSearchPath", "schema", interpreterSearchPath);
@ -5172,6 +5210,15 @@ public class Settings
return false;
}
}
if (parseRetainCommentsBetweenQueries == null) {
if (other.parseRetainCommentsBetweenQueries!= null) {
return false;
}
} else {
if (!parseRetainCommentsBetweenQueries.equals(other.parseRetainCommentsBetweenQueries)) {
return false;
}
}
if (parseMetaDefaultExpressions == null) {
if (other.parseMetaDefaultExpressions!= null) {
return false;
@ -5340,6 +5387,7 @@ public class Settings
result = ((prime*result)+((parseIgnoreComments == null)? 0 :parseIgnoreComments.hashCode()));
result = ((prime*result)+((parseIgnoreCommentStart == null)? 0 :parseIgnoreCommentStart.hashCode()));
result = ((prime*result)+((parseIgnoreCommentStop == null)? 0 :parseIgnoreCommentStop.hashCode()));
result = ((prime*result)+((parseRetainCommentsBetweenQueries == null)? 0 :parseRetainCommentsBetweenQueries.hashCode()));
result = ((prime*result)+((parseMetaDefaultExpressions == null)? 0 :parseMetaDefaultExpressions.hashCode()));
result = ((prime*result)+((applyWorkaroundFor7962 == null)? 0 :applyWorkaroundFor7962 .hashCode()));
result = ((prime*result)+((interpreterSearchPath == null)? 0 :interpreterSearchPath.hashCode()));

View File

@ -791,15 +791,33 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
static final Set<SQLDialect> SUPPORTS_HASH_COMMENT_SYNTAX = SQLDialect.supportedBy(MARIADB, MYSQL);
static final Pattern P_TRIM = Pattern.compile("^ *\\r?\\n?(.*?) *$");
final Queries parse() {
return wrap(() -> {
List<Query> result = new ArrayList<>();
Query query;
int p = positionBeforeWhitespace;
do {
parseDelimiterSpecifications();
while (parseDelimiterIf(false));
while (parseDelimiterIf(false))
p = positionBeforeWhitespace;
skipWhitespace:
if (TRUE.equals(settings().isParseRetainCommentsBetweenQueries()) && p < position) {
retainWhitespace: {
for (int i = p; i < position; i++)
if (character(i) != ' ')
break retainWhitespace;
break skipWhitespace;
}
result.add(new IgnoreQuery(P_TRIM.matcher(substring(p, position)).replaceFirst("$1")));
}
query = patchParsedQuery(parseQuery(false, false));
if (query == IGNORE || query == IGNORE_NO_DELIMITER)
@ -807,7 +825,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
if (query != null)
result.add(query);
}
while (parseDelimiterIf(true) && !done());
while (parseDelimiterIf(true) && (p = positionBeforeWhitespace) >= 0 && !done());
return done("Unexpected token or missing query delimiter", dsl.queries(result));
});
@ -13366,9 +13384,9 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
}
private final boolean parseWhitespaceIf() {
int p = position();
position(afterWhitespace(p));
return p != position();
positionBeforeWhitespace = position();
position(afterWhitespace(positionBeforeWhitespace));
return positionBeforeWhitespace != position();
}
private final int afterWhitespace(int p) {
@ -13698,17 +13716,25 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
"FOR"
};
private static final DDLQuery IGNORE = new IgnoreQuery();
private static final Query IGNORE_NO_DELIMITER = new IgnoreQuery();
private static final DDLQuery IGNORE = new IgnoreQuery();
private static final Query IGNORE_NO_DELIMITER = new IgnoreQuery();
static final class IgnoreQuery extends AbstractDDLQuery implements UEmpty {
private final String sql;
private static final class IgnoreQuery extends AbstractDDLQuery implements UEmpty {
IgnoreQuery() {
this("/* ignored */");
}
IgnoreQuery(String sql) {
super(CTX.configuration());
this.sql = sql;
}
@Override
public void accept(Context<?> ctx) {
ctx.sql("/* ignored */");
ctx.sql(sql);
}
}
@ -13719,6 +13745,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
private final ParseWithMetaLookups metaLookups;
private boolean metaLookupsForceIgnore;
private final Consumer<Param<?>> bindParamListener;
private int positionBeforeWhitespace;
private int position = 0;
private boolean ignoreHints = true;
private final Object[] bindings;

View File

@ -58,6 +58,7 @@ import org.jooq.Query;
import org.jooq.ResultQuery;
import org.jooq.Results;
import org.jooq.Traverser;
import org.jooq.impl.DefaultParseContext.IgnoreQuery;
import org.jooq.impl.QOM.MList;
import org.jooq.QueryPart;
import org.jooq.impl.ResultsImpl.ResultOrRowsImpl;
@ -151,7 +152,10 @@ final class QueriesImpl extends AbstractAttachableQueryPart implements Queries {
else
ctx.formatSeparator();
ctx.visit(query).sql(';');
ctx.visit(query);
if (!(query instanceof IgnoreQuery))
ctx.sql(';');
}
}

View File

@ -705,6 +705,16 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
<element name="parseIgnoreCommentStop" type="string" minOccurs="0" maxOccurs="1" default="[jooq ignore stop]">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#8325] The ignore comment stop token]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="parseRetainCommentsBetweenQueries" type="boolean" minOccurs="0" maxOccurs="1" default="false">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#12538] Whether the parser should retain comments and whitespace between queries when parsing multiple queries through {@link org.jooq.Parser#parse(String)}.
<p>
jOOQ's query object model doesn't have a way to represent comments
or other whitespace, and as such, the parser simply skips them by default.
However, it may be desirable to retain comments before or in between top
level queries, when parsing multiple such queries in a script. Comments
inside of queries (including procedural statements) are still not supported.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="parseMetaDefaultExpressions" type="boolean" minOccurs="0" maxOccurs="1" default="true">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#8469] Whether to parse default expressions retrieved from {@link java.sql.DatabaseMetaData}.]]></jxb:javadoc></jxb:property></appinfo></annotation>