File tree

9 files changed

+4364
-7
lines changed

9 files changed

+4364
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ plugins {
2626
id 'org.hidetake.ssh' version "latest.release"
2727

2828
id "se.bjurr.gitchangelog.git-changelog-gradle-plugin" version "latest.release"
29-
id "me.champeau.jmh" version "latest.release"
29+
id "me.champeau.jmh" version "0.7.3"
3030
id "com.nwalsh.gradle.saxon.saxon-gradle" version "latest.release"
3131
id 'biz.aQute.bnd.builder' version "latest.release"
3232
}
@@ -118,6 +118,9 @@ dependencies {
118118
testImplementation('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true }
119119
javacc('org.javacc:core:8.1.0-SNAPSHOT') { changing = true }
120120
javacc('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true }
121+
122+
jmh 'org.openjdk.jmh:jmh-core:1.37'
123+
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
121124
}
122125
configurations.configureEach {
123126
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
@@ -641,3 +644,10 @@ tasks.register('upload') {
641644
check {
642645
dependsOn jacocoTestCoverageVerification
643646
}
647+
648+
jmh {
649+
includes = ['.*JSQLParserBenchmark.*']
650+
warmupIterations = 3
651+
iterations = 3
652+
timeOnIteration = '1s'
653+
}
Original file line numberDiff line numberDiff line change
@@ -3681,7 +3681,7 @@ FromItem FromItem() #FromItem:
36813681
|
36823682
LOOKAHEAD(3) fromItem=Table()
36833683
|
3684-
LOOKAHEAD(110) fromItem = ParenthesedFromItem()
3684+
LOOKAHEAD(ParenthesedFromItem()) fromItem = ParenthesedFromItem()
36853685
|
36863686
LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) (
36873687
fromItem=ParenthesedSelect()
@@ -4508,7 +4508,7 @@ Expression AndExpression() :
45084508
}
45094509
{
45104510
(
4511-
LOOKAHEAD(814, {!interrupted}) left=Condition()
4511+
LOOKAHEAD(Condition(), {!interrupted}) left=Condition()
45124512
|
45134513
[ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
45144514
"(" left=XorExpression() ")" {left = new ParenthesedExpressionList(left); if (not) { left = new NotExpression(left, exclamationMarkNot); not = false; } }
@@ -4519,7 +4519,7 @@ Expression AndExpression() :
45194519
{ boolean useOperator = false; }
45204520
(<K_AND> | <OP_DOUBLEAND> {useOperator=true;} )
45214521
(
4522-
LOOKAHEAD(814, {!interrupted}) right=Condition()
4522+
LOOKAHEAD(Condition(), {!interrupted}) right=Condition()
45234523
|
45244524
[ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
45254525
"(" right=XorExpression() ")" {right = new ParenthesedExpressionList(right); if (not) { right = new NotExpression(right, exclamationMarkNot); not = false; } }
@@ -4545,7 +4545,7 @@ Expression Condition():
45454545
{
45464546
[ LOOKAHEAD(2) (<K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; })]
45474547
(
4548-
LOOKAHEAD(814, {!interrupted}) result=RegularCondition()
4548+
LOOKAHEAD(RegularCondition(), {!interrupted}) result=RegularCondition()
45494549
|
45504550
result=SQLCondition()
45514551
)
@@ -4648,7 +4648,7 @@ Expression SQLCondition():
46484648
{
46494649
(
46504650
result=ExistsExpression()
4651-
| LOOKAHEAD( 814, {!interrupted}) result=OverlapsCondition()
4651+
| LOOKAHEAD( OverlapsCondition(), {!interrupted}) result=OverlapsCondition()
46524652
| left = SimpleExpression() { result = left; }
46534653
[
46544654
LOOKAHEAD(2) (
@@ -5387,7 +5387,7 @@ Expression PrimaryExpression() #PrimaryExpression:
53875387

53885388
| LOOKAHEAD(16) retval=AllTableColumns()
53895389

5390-
| LOOKAHEAD(250) retval=FunctionAllColumns()
5390+
| LOOKAHEAD(FunctionAllColumns()) retval=FunctionAllColumns()
53915391

53925392
// support timestamp expressions
53935393
| LOOKAHEAD(2, {!interrupted}) (token=<K_TIME_KEY_EXPR> | token=<K_CURRENT>) { retval = new TimeKeyExpression(token.image); }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Benchmark (version) Mode Cnt Score Error Units
2+
JSQLParserBenchmark.parseSQLStatements latest avgt 15 264.132 ± 9.636 ms/op
3+
JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 415.744 ± 20.602 ms/op
4+
JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 89.387 ± 1.916 ms/op
5+
JSQLParserBenchmark.parseSQLStatements 5.0 avgt 15 68.810 ± 2.591 ms/op
6+
JSQLParserBenchmark.parseSQLStatements 4.9 avgt 15 60.515 ± 1.650 ms/op
7+
JSQLParserBenchmark.parseSQLStatements 4.8 avgt 15 60.002 ± 1.259 ms/op
8+
JSQLParserBenchmark.parseSQLStatements 4.7 avgt 15 73.291 ± 3.049 ms/op
9+
10+
Benchmark (version) Mode Cnt Score Error Units
11+
JSQLParserBenchmark.parseSQLStatements latest avgt 15 249.408 ± 11.340 ms/op
12+
JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 ms/op
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package net.sf.jsqlparser.benchmark;
2+
3+
import net.sf.jsqlparser.parser.CCJSqlParser;
4+
import net.sf.jsqlparser.statement.Statements;
5+
6+
import java.lang.reflect.Method;
7+
import java.net.URLClassLoader;
8+
import java.util.concurrent.ExecutorService;
9+
import java.util.function.Consumer;
10+
11+
public class DynamicParserRunner implements SqlParserRunner {
12+
private final Method parseStatementsMethod;
13+
14+
public DynamicParserRunner(URLClassLoader loader) throws Exception {
15+
Class<?> utilClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParserUtil");
16+
Class<?> ccjClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParser");
17+
Class<?> consumerClass = Class.forName("java.util.function.Consumer"); // interface OK
18+
parseStatementsMethod = utilClass.getMethod(
19+
"parseStatements",
20+
String.class,
21+
ExecutorService.class,
22+
consumerClass
23+
);
24+
}
25+
26+
@Override
27+
public Statements parseStatements(String sql,
28+
ExecutorService executorService,
29+
Consumer<CCJSqlParser> consumer) throws Exception {
30+
return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null);
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package net.sf.jsqlparser.benchmark;
2+
3+
import net.sf.jsqlparser.parser.CCJSqlParser;
4+
import net.sf.jsqlparser.statement.Statements;
5+
import org.openjdk.jmh.annotations.*;
6+
7+
import java.io.IOException;
8+
import java.io.InputStream;
9+
import java.net.URL;
10+
import java.net.URLClassLoader;
11+
import java.nio.charset.StandardCharsets;
12+
import java.nio.file.*;
13+
import java.util.concurrent.*;
14+
import java.util.function.Consumer;
15+
16+
@BenchmarkMode(Mode.AverageTime)
17+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
18+
@State(Scope.Benchmark)
19+
public class JSQLParserBenchmark {
20+
21+
private String sqlContent;
22+
private ExecutorService executorService;
23+
24+
SqlParserRunner runner;
25+
26+
//@Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" })
27+
@Param({ "latest", "5.2" })
28+
public String version;
29+
30+
@Setup(Level.Trial)
31+
public void setup() throws Exception {
32+
if ("latest".equals(version)) {
33+
runner = new LatestClasspathRunner(); // direct call, no reflection
34+
} else {
35+
Path jarPath = downloadJsqlparserJar(version);
36+
URLClassLoader loader = new URLClassLoader(new URL[]{ jarPath.toUri().toURL() }, null);
37+
runner = new DynamicParserRunner(loader);
38+
}
39+
40+
// Adjust path as necessary based on where source root is during test execution
41+
Path path = Paths.get("src/test/resources/net/sf/jsqlparser/performance.sql");
42+
sqlContent = Files.readString(path, StandardCharsets.UTF_8);
43+
executorService = Executors.newSingleThreadExecutor();
44+
}
45+
46+
private Path downloadJsqlparserJar(String version) throws IOException {
47+
String jarUrl = String.format(
48+
"https://repo1.maven.org/maven2/com//jsqlparser/jsqlparser/%s/jsqlparser-%s.jar",
49+
version, version
50+
);
51+
52+
Path cacheDir = Paths.get("build/libs/downloaded-jars");
53+
Files.createDirectories(cacheDir);
54+
Path jarFile = cacheDir.resolve("jsqlparser-" + version + ".jar");
55+
56+
if (!Files.exists(jarFile)) {
57+
System.out.println("Downloading " + version);
58+
try (InputStream in = new URL(jarUrl).openStream()) {
59+
Files.copy(in, jarFile);
60+
}
61+
}
62+
63+
return jarFile;
64+
}
65+
66+
@Benchmark
67+
public void parseSQLStatements() throws Exception {
68+
final Statements statements = runner.parseStatements(
69+
sqlContent,
70+
executorService,
71+
(Consumer<CCJSqlParser>) parser -> {
72+
// No-op consumer (or you can log/validate each parser if desired)
73+
}
74+
);
75+
assert statements.size()==4;
76+
}
77+
78+
@TearDown(Level.Trial)
79+
public void tearDown() {
80+
executorService.shutdown();
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package net.sf.jsqlparser.benchmark;
2+
3+
import net.sf.jsqlparser.parser.CCJSqlParser;
4+
import net.sf.jsqlparser.statement.Statements;
5+
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.function.Consumer;
8+
9+
public class LatestClasspathRunner implements SqlParserRunner {
10+
11+
@Override
12+
public Statements parseStatements(String sql,
13+
ExecutorService executorService,
14+
Consumer<CCJSqlParser> consumer) throws Exception {
15+
return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService, consumer);
16+
}
17+
}
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package net.sf.jsqlparser.benchmark;
2+
3+
import net.sf.jsqlparser.parser.CCJSqlParser;
4+
import net.sf.jsqlparser.statement.Statements;
5+
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.function.Consumer;
8+
9+
public interface SqlParserRunner {
10+
Statements parseStatements(String sql, ExecutorService executorService, Consumer<CCJSqlParser> consumer) throws Exception;
11+
}

0 commit comments

Comments
 (0)