Skip to content

Commit

Permalink
Improved performance of comma and AND/OR removal regular expressions. (
Browse files Browse the repository at this point in the history
  • Loading branch information
HidekiSugimoto189 authored Nov 5, 2023
1 parent 217d183 commit f265e6d
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,12 @@ public boolean contains(final Object o) {
}

/** where句の直後にくるANDやORを除外するための正規表現 */
protected static final Pattern WHERE_CLAUSE_PATTERN = Pattern
.compile("(?i)(?<clause>(^|\\s+)(WHERE\\s+(--.*|/\\*[^(/\\*|\\*/)]+?\\*/\\s*)*\\s*))(AND\\s+|OR\\s+)");
protected static final Pattern WHERE_CLAUSE_PATTERN = Pattern.compile(
"(?i)(?<clause>(\\bWHERE\\s+(--.*|/\\*[^(/\\*|\\*/)]+?\\*/\\s*)*\\s*))((AND|OR)\\s+)");

/** 各句の最初に現れるカンマを除去するための正規表現 */
protected static final Pattern REMOVE_FIRST_COMMA_PATTERN = Pattern
.compile(
"(?i)(?<keyword>((^|\\s+)(SELECT|ORDER\\s+BY|GROUP\\s+BY|SET)\\s+|\\(\\s*)(--.*|/\\*[^(/\\*|\\*/)]+?\\*/\\s*)*\\s*)(,)");
protected static final Pattern REMOVE_FIRST_COMMA_PATTERN = Pattern.compile(
"(?i)(?<keyword>(\\b(SELECT|ORDER\\s+BY|GROUP\\s+BY|SET)\\s+|\\(\\s*)(--.*|/\\*[^(/\\*|\\*/)]+?\\*/\\s*)*\\s*),");

/** 不要な空白、改行を除去するための正規表現 */
protected static final Pattern CLEAR_BLANK_PATTERN = Pattern.compile("(?m)^\\s*(\\r\\n|\\r|\\n)");
Expand Down Expand Up @@ -327,7 +326,7 @@ public String getSchema() {
* @see jp.co.future.uroborosql.context.SqlContext#setSchema(java.lang.String)
*/
@Override
public SqlContext setSchema(String schema) {
public SqlContext setSchema(final String schema) {
this.schema = schema;
return this;
}
Expand Down Expand Up @@ -531,7 +530,7 @@ public <V> SqlContext paramListIfAbsent(final String parameterName,
@Override
public SqlContext paramMap(final Map<String, Object> paramMap) {
if (paramMap != null) {
paramMap.forEach((k, v) -> param(k, v));
paramMap.forEach(this::param);
}
return this;
}
Expand Down Expand Up @@ -979,7 +978,7 @@ public SqlContext addBatch() {
* @param baseSize 基底となるMapのサイズ
* @return 初期容量
*/
private int calcInitialCapacity(int baseSize) {
private int calcInitialCapacity(final int baseSize) {
// MapのloadFactorはデフォルト0.75(3/4)なので 4/3 を掛けてcapacityを計算する。そのうえで切り捨てが発生してもキャパシティを越えないよう +1 している。
return baseSize * 4 / 3 + 1;
}
Expand Down Expand Up @@ -1269,7 +1268,7 @@ public Function<SqlContext, Integer> getUpdateDelegate() {
* @see jp.co.future.uroborosql.context.SqlContext#setUpdateDelegate(java.util.function.Function)
*/
@Override
public SqlContext setUpdateDelegate(Function<SqlContext, Integer> updateDelegate) {
public SqlContext setUpdateDelegate(final Function<SqlContext, Integer> updateDelegate) {
this.updateDelegate = updateDelegate;
return this;
}
Expand Down
101 changes: 90 additions & 11 deletions src/test/java/jp/co/future/uroborosql/context/SqlContextImplTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package jp.co.future.uroborosql.context;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.sql.JDBCType;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -17,6 +27,8 @@

import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jp.co.future.uroborosql.UroboroSQL;
import jp.co.future.uroborosql.config.SqlConfig;
Expand All @@ -27,6 +39,9 @@
import jp.co.future.uroborosql.parser.SqlParserImpl;

public class SqlContextImplTest {
/** ロガー */
protected static final Logger log = LoggerFactory.getLogger(SqlContextImplTest.class);

private static SqlConfig config = null;

@BeforeClass
Expand All @@ -42,7 +57,7 @@ private SqlContext getSqlContext(final String sql) {
}

private String replaceLineSep(final String sql) {
return sql.replaceAll("\\[LF\\]", System.lineSeparator());
return sql.replace("[LF]", System.lineSeparator());
}

@Test
Expand Down Expand Up @@ -88,6 +103,17 @@ public void removeFirstAndKeyWordWhenWhereClause() throws Exception {
SqlContext ctx62 = getSqlContext("select * from test[LF]where /* comment */ --comment [LF] order = 1");
assertEquals(replaceLineSep("select * from test[LF]where /* comment */ --comment [LF] order = 1"),
ctx62.getExecutableSql());

Instant startTime = Instant.now(Clock.systemDefaultZone());
String sql = replaceLineSep("select * from test[LF]where -- /* comment */ [LF] and aaa = 1");
for (int i = 0; i < 1000000; i++) {
SqlContext timeCtx = config.contextWith(sql);
timeCtx.addSqlPart(sql);
timeCtx.getExecutableSql();
}
log.info("removeFirstAndKeyWordWhenWhereClause elapsed time. {}",
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS").format(
LocalTime.MIDNIGHT.plus(Duration.between(startTime, Instant.now(Clock.systemDefaultZone())))));
}

@Test
Expand Down Expand Up @@ -126,6 +152,18 @@ public void removeFirstCommaWhenSelectClause() throws Exception {
assertEquals(replaceLineSep(
"with dummy as ( select * from dummy )[LF]select /* コメント:japanese comment */ [LF] aaa[LF], bbb[LF], ccc from test"),
ctx8.getExecutableSql());

Instant startTime = Instant.now(Clock.systemDefaultZone());
String sql = replaceLineSep(
"with dummy as ( select * from dummy )[LF]select /* コメント:japanese comment */ [LF], aaa[LF], bbb[LF], ccc from test");
for (int i = 0; i < 1000000; i++) {
SqlContext timeCtx = config.contextWith(sql);
timeCtx.addSqlPart(sql);
timeCtx.getExecutableSql();
}
log.info("removeFirstCommaWhenSelectClause elapsed time. {}",
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS").format(
LocalTime.MIDNIGHT.plus(Duration.between(startTime, Instant.now(Clock.systemDefaultZone())))));
}

@Test
Expand Down Expand Up @@ -165,6 +203,17 @@ public void removeFirstCommaWhenOrderByClause() throws Exception {
SqlContext ctx62 = getSqlContext("select * from test[LF]order by --/* comment */[LF], aaa, bbb");
assertEquals(replaceLineSep("select * from test[LF]order by --/* comment */[LF] aaa, bbb"),
ctx62.getExecutableSql());

Instant startTime = Instant.now(Clock.systemDefaultZone());
String sql = replaceLineSep("select * from test[LF]order by --/* comment */[LF], aaa, bbb");
for (int i = 0; i < 1000000; i++) {
SqlContext timeCtx = config.contextWith(sql);
timeCtx.addSqlPart(sql);
timeCtx.getExecutableSql();
}
log.info("removeFirstCommaWhenOrderByClause elapsed time. {}",
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS").format(
LocalTime.MIDNIGHT.plus(Duration.between(startTime, Instant.now(Clock.systemDefaultZone())))));
}

@Test
Expand Down Expand Up @@ -204,6 +253,18 @@ public void removeFirstCommaWhenGroupByClause() throws Exception {
SqlContext ctx62 = getSqlContext("select * from test[LF]group by /* comment */ --aaa[LF], aaa, bbb");
assertEquals(replaceLineSep("select * from test[LF]group by /* comment */ --aaa[LF] aaa, bbb"),
ctx62.getExecutableSql());

Instant startTime = Instant.now(Clock.systemDefaultZone());
String sql = replaceLineSep("select * from test[LF]group by /* comment */ --aaa[LF], aaa, bbb");
for (int i = 0; i < 1000000; i++) {
SqlContext timeCtx = config.contextWith(sql);
timeCtx.addSqlPart(sql);
timeCtx.getExecutableSql();
}
log.info("removeFirstCommaWhenGroupByClause elapsed time. {}",
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS").format(
LocalTime.MIDNIGHT.plus(Duration.between(startTime, Instant.now(Clock.systemDefaultZone())))));

}

@Test
Expand Down Expand Up @@ -255,6 +316,18 @@ public void removeFirstCommaWhenStartBracket() throws Exception {
replaceLineSep(
"insert into[LF](--comment[LF] aaa[LF], bbb[LF], ccc[LF]) values (/*comment*/[LF]111,[LF]222,[LF]333[LF])"),
ctx52.getExecutableSql());

Instant startTime = Instant.now(Clock.systemDefaultZone());
String sql = replaceLineSep(
"insert into[LF](--comment[LF], aaa[LF], bbb[LF], ccc[LF]) values (,/*comment*/[LF]111,[LF]222,[LF]333[LF])");
for (int i = 0; i < 1000000; i++) {
SqlContext timeCtx = config.contextWith(sql);
timeCtx.addSqlPart(sql);
timeCtx.getExecutableSql();
}
log.info("removeFirstCommaWhenStartBracket elapsed time. {}",
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS").format(
LocalTime.MIDNIGHT.plus(Duration.between(startTime, Instant.now(Clock.systemDefaultZone())))));
}

@Test
Expand Down Expand Up @@ -307,6 +380,17 @@ public void removeFirstCommaWhenSetClause() throws Exception {
"select[LF], aaa,[LF]code_set,[LF]bbb,[LF]ccc[LF]from[LF]test[LF]where[LF]1 = 1");
assertEquals(replaceLineSep("select[LF] aaa,[LF]code_set,[LF]bbb,[LF]ccc[LF]from[LF]test[LF]where[LF]1 = 1"),
ctx63.getExecutableSql());

Instant startTime = Instant.now(Clock.systemDefaultZone());
String sql = replaceLineSep("select[LF], aaa,[LF]code_set,[LF]bbb,[LF]ccc[LF]from[LF]test[LF]where[LF]1 = 1");
for (int i = 0; i < 1000000; i++) {
SqlContext timeCtx = config.contextWith(sql);
timeCtx.addSqlPart(sql);
timeCtx.getExecutableSql();
}
log.info("removeFirstCommaWhenSetClause elapsed time. {}",
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS").format(
LocalTime.MIDNIGHT.plus(Duration.between(startTime, Instant.now(Clock.systemDefaultZone())))));
}

@Test
Expand All @@ -333,9 +417,8 @@ public void testHasParam() throws Exception {
@SuppressWarnings("deprecation")
@Test
public void testParamList() throws Exception {
SqlContext ctx = null;
SqlContext ctx = getSqlContext("select * from dummy");

ctx = getSqlContext("select * from dummy");
ctx.paramList("key1", "value1");
assertThat(ctx.getParam("key1").getValue(), is(Arrays.asList("value1")));

Expand All @@ -352,18 +435,15 @@ public void testParamList() throws Exception {
assertThat(ctx.getParam("key1").getValue(), is(values));

ctx = getSqlContext("select * from dummy");
ctx.paramList("key1", () -> {
return values;
});
ctx.paramList("key1", () -> values);
assertThat(ctx.getParam("key1").getValue(), is(values));
}

@SuppressWarnings("deprecation")
@Test
public void testIfAbsent() throws Exception {
SqlContext ctx = null;
SqlContext ctx = getSqlContext("select * from dummy");

ctx = getSqlContext("select * from dummy");
ctx.paramIfAbsent("key1", "value1");
assertThat(ctx.getParam("key1").getValue(), is("value1"));
ctx.paramIfAbsent("key1", "value2");
Expand Down Expand Up @@ -687,7 +767,6 @@ public static class TestEntity {
private Optional<String> memo = Optional.empty();

public TestEntity(final int id, final String name, final int age, final Optional<String> memo) {
super();
this.id = id;
this.name = name;
this.age = age;
Expand Down

0 comments on commit f265e6d

Please sign in to comment.