diff --git a/src/main/java/jp/co/future/uroborosql/dialect/MariaDb10Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/MariaDb10Dialect.java
new file mode 100644
index 00000000..d7044c35
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/MariaDb10Dialect.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+/**
+ * MariaDB(ver10とそれ以降)用のDialect
+ *
+ * @author H.Sugimoto
+ */
+public class MariaDb10Dialect extends MariaDbDialect {
+ /**
+ * コンストラクタ
+ */
+ public MariaDb10Dialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.MariaDbDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion >= 10;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.MariaDbDialect#supportsSequence()
+ */
+ @Override
+ public boolean supportsSequence() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#getSequenceNextValSql(java.lang.String)
+ */
+ @Override
+ public String getSequenceNextValSql(final String sequenceName) {
+ return "nextval(" + sequenceName + ")";
+ }
+
+}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/MariaDb5Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/MariaDb5Dialect.java
new file mode 100644
index 00000000..136dad77
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/MariaDb5Dialect.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+/**
+ * MariaDB(ver5)用のDialect
+ *
+ * @author H.Sugimoto
+ */
+public class MariaDb5Dialect extends MariaDbDialect {
+ /**
+ * コンストラクタ
+ */
+ public MariaDb5Dialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.MariaDbDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion == 5;
+ }
+
+}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/MariaDbDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/MariaDbDialect.java
new file mode 100644
index 00000000..fbe7e1ab
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/MariaDbDialect.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.exception.UroborosqlRuntimeException;
+
+/**
+ * MariaDB用のデフォルト設定用Dialect
+ *
+ * @author H.Sugimoto
+ */
+public abstract class MariaDbDialect extends AbstractDialect {
+ /**
+ * 悲観ロックのErrorCode もしくは SqlState. MySQLの場合はErrorCodeで判定する.
+ *
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.
+ */
+ private static final Set pessimisticLockingErrorCodes = Set.of("3572");
+
+ /**
+ * コンストラクタ
+ */
+ protected MariaDbDialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#accept(jp.co.future.uroborosql.connection.ConnectionSupplier)
+ */
+ @Override
+ public boolean accept(final ConnectionSupplier supplier) {
+ if (supplier == null) {
+ return false;
+ }
+
+ var parts = supplier.getDatabaseName().split("-", 2);
+ var databaseName = parts[0];
+
+ if (!databaseName.startsWith(getDatabaseName())) {
+ return false;
+ }
+
+ var databaseVersion = parts[1];
+
+ try {
+ var majorVersion = Integer.parseInt(databaseVersion.substring(0, databaseVersion.indexOf(".")));
+ return isTargetVersion(majorVersion);
+ } catch (NumberFormatException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * 対象のMariaDBバージョンかどうかを判定する
+ *
+ * @param majorVersion コネクションから取得したメジャーバージョン
+ * @return 対象のバージョンの場合true
+ */
+ protected abstract boolean isTargetVersion(int majorVersion);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName()
+ */
+ @Override
+ public String getDatabaseName() {
+ return "MariaDB";
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#supportsBulkInsert()
+ */
+ @Override
+ public boolean supportsBulkInsert() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#supportsLimitClause()
+ */
+ @Override
+ public boolean supportsLimitClause() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#supportsSequence()
+ */
+ @Override
+ public boolean supportsSequence() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#supportsForUpdateWait()
+ */
+ @Override
+ public boolean supportsForUpdateWait() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#supportsOptimizerHints()
+ */
+ @Override
+ public boolean supportsOptimizerHints() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#getSequenceNextValSql(java.lang.String)
+ */
+ @Override
+ public String getSequenceNextValSql(final String sequenceName) {
+ throw new UroborosqlRuntimeException("MariaDB does not support Sequence.");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#addOptimizerHints(java.lang.StringBuilder, java.util.List)
+ */
+ @Override
+ public StringBuilder addOptimizerHints(final StringBuilder sql, final List hints) {
+ var hintStr = "$1 " + hints.stream().collect(Collectors.joining(" ")) + System.lineSeparator();
+ return new StringBuilder(sql.toString().replaceFirst("((FROM|from)\\s+[^\\s]+)\\s*", hintStr));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#getPessimisticLockingErrorCodes()
+ */
+ @Override
+ public Set getPessimisticLockingErrorCodes() {
+ return pessimisticLockingErrorCodes;
+ }
+
+}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java
index 61217bb3..74e2cb78 100644
--- a/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java
+++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java
@@ -7,7 +7,7 @@
package jp.co.future.uroborosql.dialect;
/**
- * Oracle12(以降のバージョンも含む)用のDialect
+ * Oracle12用のDialect
*
* @author H.Sugimoto
*/
@@ -19,6 +19,16 @@ public Oracle12Dialect() {
super('\\', new char[] { '%', '_', '%', '_' });
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.OracleDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion == 12;
+ }
+
/**
* {@inheritDoc}
*
@@ -61,14 +71,4 @@ public String getLimitClause(final long limit, final long offset) {
}
return builder.toString();
}
-
- /**
- * {@inheritDoc}
- *
- * @see jp.co.future.uroborosql.dialect.OracleDialect#isTargetVersion(int)
- */
- @Override
- protected boolean isTargetVersion(final int majorVersion) {
- return majorVersion >= 12;
- }
}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle18Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle18Dialect.java
new file mode 100644
index 00000000..17898f75
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle18Dialect.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+/**
+ * Oracle18用のDialect
+ *
+ * @author H.Sugimoto
+ */
+public class Oracle18Dialect extends Oracle12Dialect {
+ /**
+ * コンストラクタ
+ */
+ public Oracle18Dialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.OracleDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion == 18;
+ }
+}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle19Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle19Dialect.java
new file mode 100644
index 00000000..4c244443
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle19Dialect.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+/**
+ * Oracle19用のDialect
+ *
+ * @author H.Sugimoto
+ */
+public class Oracle19Dialect extends Oracle12Dialect {
+ /**
+ * コンストラクタ
+ */
+ public Oracle19Dialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.OracleDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion == 19;
+ }
+}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle21Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle21Dialect.java
new file mode 100644
index 00000000..bb9a1708
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle21Dialect.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+/**
+ * Oracle21用のDialect
+ *
+ * @author H.Sugimoto
+ */
+public class Oracle21Dialect extends Oracle12Dialect {
+ /**
+ * コンストラクタ
+ */
+ public Oracle21Dialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.OracleDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion == 21;
+ }
+}
diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle23Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle23Dialect.java
new file mode 100644
index 00000000..9b5ca596
--- /dev/null
+++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle23Dialect.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2017-present, Future Corporation
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+package jp.co.future.uroborosql.dialect;
+
+/**
+ * Oracle23(以降のバージョンも含む)用のDialect
+ *
+ * @author H.Sugimoto
+ */
+public class Oracle23Dialect extends Oracle12Dialect {
+ /**
+ * コンストラクタ
+ */
+ public Oracle23Dialect() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.OracleDialect#isTargetVersion(int)
+ */
+ @Override
+ protected boolean isTargetVersion(final int majorVersion) {
+ return majorVersion >= 23;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see jp.co.future.uroborosql.dialect.Dialect#supportsBulkInsert()
+ */
+ @Override
+ public boolean supportsBulkInsert() {
+ return true;
+ }
+
+}
diff --git a/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect b/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect
index 18ca28ec..c6409291 100644
--- a/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect
+++ b/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect
@@ -1,7 +1,13 @@
+jp.co.future.uroborosql.dialect.Oracle23Dialect
+jp.co.future.uroborosql.dialect.Oracle21Dialect
+jp.co.future.uroborosql.dialect.Oracle19Dialect
+jp.co.future.uroborosql.dialect.Oracle18Dialect
jp.co.future.uroborosql.dialect.Oracle12Dialect
jp.co.future.uroborosql.dialect.Oracle11Dialect
jp.co.future.uroborosql.dialect.Oracle10Dialect
jp.co.future.uroborosql.dialect.MsSqlDialect
+jp.co.future.uroborosql.dialect.MariaDb10Dialect
+jp.co.future.uroborosql.dialect.MariaDb5Dialect
jp.co.future.uroborosql.dialect.MySqlDialect
jp.co.future.uroborosql.dialect.PostgresqlDialect
jp.co.future.uroborosql.dialect.H2Dialect
\ No newline at end of file
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/MariaDb10DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/MariaDb10DialectTest.java
new file mode 100644
index 00000000..5c109add
--- /dev/null
+++ b/src/test/java/jp/co/future/uroborosql/dialect/MariaDb10DialectTest.java
@@ -0,0 +1,211 @@
+package jp.co.future.uroborosql.dialect;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import jp.co.future.uroborosql.connection.ConnectionContext;
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.enums.ForUpdateType;
+
+/**
+ * MariaDb10Dialectの個別実装部分のテストケース
+ *
+ * @author H.Sugimoto
+ *
+ */
+public class MariaDb10DialectTest {
+ private final Dialect dialect = new MariaDb10Dialect();
+
+ @Test
+ void testAccept5() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "MariaDB-5.0";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(MariaDb10Dialect.class)));
+ }
+
+ @Test
+ void testAccept10() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "MariaDB-10.0";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(MariaDb10Dialect.class));
+ }
+
+ @Test
+ void testAccept11() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "MariaDB-11.0";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(MariaDb10Dialect.class));
+ }
+
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThat(dialect.getSequenceNextValSql("test_sequence"), is("nextval(test_sequence)"));
+ }
+
+ @Test
+ void testEscapeLikePattern() {
+ assertThat(dialect.escapeLikePattern(""), is(""));
+ assertThat(dialect.escapeLikePattern(null), nullValue());
+ assertThat(dialect.escapeLikePattern("pattern"), is("pattern"));
+ assertThat(dialect.escapeLikePattern("%pattern"), is("$%pattern"));
+ assertThat(dialect.escapeLikePattern("_pattern"), is("$_pattern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat$%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat$_tern"));
+ assertThat(dialect.escapeLikePattern("pattern%"), is("pattern$%"));
+ assertThat(dialect.escapeLikePattern("pattern_"), is("pattern$_"));
+ assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat_tern"));
+ }
+
+ @Test
+ void testGetEscapeChar() {
+ assertThat(dialect.getEscapeChar(), is('$'));
+ }
+
+ @Test
+ void testSupports() {
+ assertThat(dialect.supportsBulkInsert(), is(true));
+ assertThat(dialect.supportsLimitClause(), is(true));
+ assertThat(dialect.supportsNullValuesOrdering(), is(false));
+ assertThat(dialect.supportsIdentity(), is(true));
+ assertThat(dialect.supportsSequence(), is(true));
+ assertThat(dialect.isRemoveTerminator(), is(true));
+ assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false));
+ assertThat(dialect.supportsForUpdate(), is(true));
+ assertThat(dialect.supportsForUpdateNoWait(), is(true));
+ assertThat(dialect.supportsForUpdateWait(), is(false));
+ assertThat(dialect.supportsOptimizerHints(), is(true));
+ assertThat(dialect.supportsEntityBulkUpdateOptimisticLock(), is(true));
+ }
+
+ @Test
+ void testGetLimitClause() {
+ assertThat(dialect.getLimitClause(3, 5), is("LIMIT 3 OFFSET 5" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 5), is("OFFSET 5" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(3, 0), is("LIMIT 3 " + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 0), is(""));
+ }
+
+ @Test
+ void testAddForUpdateClause() {
+ var sql = new StringBuilder("SELECT * FROM test WHERE 1 = 1 ORDER id").append(System.lineSeparator());
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NORMAL, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NOWAIT, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE NOWAIT"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.WAIT, 10).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE WAIT 10"));
+ }
+
+ @Test
+ void testAddOptimizerHints1() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM test")
+ .append(System.lineSeparator())
+ .append("WHERE 1 = 1 ORDER id")
+ .append(System.lineSeparator());
+ List hints = new ArrayList<>();
+ hints.add("INDEX (test test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT" + System.lineSeparator()
+ + " * FROM test INDEX (test test_ix) USE_NL"
+ + System.lineSeparator()
+ + "WHERE 1 = 1 ORDER id"
+ + System.lineSeparator()));
+ }
+
+ @Test
+ void testAddOptimizerHints2() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM PUBLIC.TEST_1");
+ List hints = new ArrayList<>();
+ hints.add("INDEX (PUBLIC.TEST_1 test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT"
+ + System.lineSeparator()
+ + " * FROM PUBLIC.TEST_1 INDEX (PUBLIC.TEST_1 test_ix) USE_NL"
+ + System.lineSeparator()));
+ }
+
+ @Test
+ void testGetPessimisticLockingErrorCodes() {
+ assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("3572")));
+ }
+
+}
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/MariaDb5DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/MariaDb5DialectTest.java
new file mode 100644
index 00000000..dd727fcb
--- /dev/null
+++ b/src/test/java/jp/co/future/uroborosql/dialect/MariaDb5DialectTest.java
@@ -0,0 +1,189 @@
+package jp.co.future.uroborosql.dialect;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import jp.co.future.uroborosql.connection.ConnectionContext;
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.enums.ForUpdateType;
+import jp.co.future.uroborosql.exception.UroborosqlRuntimeException;
+
+/**
+ * MariaDb5Dialectの個別実装部分のテストケース
+ *
+ * @author H.Sugimoto
+ *
+ */
+public class MariaDb5DialectTest {
+ private final Dialect dialect = new MariaDb5Dialect();
+
+ @Test
+ void testAccept5() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "MariaDB-5.0";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(MariaDb5Dialect.class));
+ }
+
+ @Test
+ void testAccept10() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "MariaDB-10.0";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(MariaDb5Dialect.class)));
+ }
+
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThrows(UroborosqlRuntimeException.class, () -> {
+ dialect.getSequenceNextValSql("test_sequence");
+ });
+ }
+
+ @Test
+ void testEscapeLikePattern() {
+ assertThat(dialect.escapeLikePattern(""), is(""));
+ assertThat(dialect.escapeLikePattern(null), nullValue());
+ assertThat(dialect.escapeLikePattern("pattern"), is("pattern"));
+ assertThat(dialect.escapeLikePattern("%pattern"), is("$%pattern"));
+ assertThat(dialect.escapeLikePattern("_pattern"), is("$_pattern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat$%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat$_tern"));
+ assertThat(dialect.escapeLikePattern("pattern%"), is("pattern$%"));
+ assertThat(dialect.escapeLikePattern("pattern_"), is("pattern$_"));
+ assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat_tern"));
+ }
+
+ @Test
+ void testGetEscapeChar() {
+ assertThat(dialect.getEscapeChar(), is('$'));
+ }
+
+ @Test
+ void testSupports() {
+ assertThat(dialect.supportsBulkInsert(), is(true));
+ assertThat(dialect.supportsLimitClause(), is(true));
+ assertThat(dialect.supportsNullValuesOrdering(), is(false));
+ assertThat(dialect.supportsIdentity(), is(true));
+ assertThat(dialect.supportsSequence(), is(false));
+ assertThat(dialect.isRemoveTerminator(), is(true));
+ assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false));
+ assertThat(dialect.supportsForUpdate(), is(true));
+ assertThat(dialect.supportsForUpdateNoWait(), is(true));
+ assertThat(dialect.supportsForUpdateWait(), is(false));
+ assertThat(dialect.supportsOptimizerHints(), is(true));
+ assertThat(dialect.supportsEntityBulkUpdateOptimisticLock(), is(true));
+ }
+
+ @Test
+ void testGetLimitClause() {
+ assertThat(dialect.getLimitClause(3, 5), is("LIMIT 3 OFFSET 5" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 5), is("OFFSET 5" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(3, 0), is("LIMIT 3 " + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 0), is(""));
+ }
+
+ @Test
+ void testAddForUpdateClause() {
+ var sql = new StringBuilder("SELECT * FROM test WHERE 1 = 1 ORDER id").append(System.lineSeparator());
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NORMAL, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NOWAIT, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE NOWAIT"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.WAIT, 10).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE WAIT 10"));
+ }
+
+ @Test
+ void testAddOptimizerHints1() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM test")
+ .append(System.lineSeparator())
+ .append("WHERE 1 = 1 ORDER id")
+ .append(System.lineSeparator());
+ List hints = new ArrayList<>();
+ hints.add("INDEX (test test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT" + System.lineSeparator()
+ + " * FROM test INDEX (test test_ix) USE_NL"
+ + System.lineSeparator()
+ + "WHERE 1 = 1 ORDER id"
+ + System.lineSeparator()));
+ }
+
+ @Test
+ void testAddOptimizerHints2() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM PUBLIC.TEST_1");
+ List hints = new ArrayList<>();
+ hints.add("INDEX (PUBLIC.TEST_1 test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT"
+ + System.lineSeparator()
+ + " * FROM PUBLIC.TEST_1 INDEX (PUBLIC.TEST_1 test_ix) USE_NL"
+ + System.lineSeparator()));
+ }
+
+ @Test
+ void testGetPessimisticLockingErrorCodes() {
+ assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("3572")));
+ }
+
+}
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java
index 4d7bdf22..6f523db0 100644
--- a/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java
+++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java
@@ -20,7 +20,7 @@
import jp.co.future.uroborosql.enums.ForUpdateType;
/**
- * Oracle10Dialectの個別実装部分のテストケース
+ * Oracle11Dialectの個別実装部分のテストケース
*
* @author H.Sugimoto
*
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java
index bb57dc0a..2482b514 100644
--- a/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java
+++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java
@@ -20,7 +20,7 @@
import jp.co.future.uroborosql.enums.ForUpdateType;
/**
- * Oracle10Dialectの個別実装部分のテストケース
+ * Oracle12Dialectの個別実装部分のテストケース
*
* @author H.Sugimoto
*
@@ -103,7 +103,7 @@ public String getDatabaseName() {
var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
.filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
- assertThat(dialect, instanceOf(Oracle12Dialect.class));
+ assertThat(dialect, not(instanceOf(Oracle12Dialect.class)));
}
@Test
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle18DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle18DialectTest.java
new file mode 100644
index 00000000..6561b4d1
--- /dev/null
+++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle18DialectTest.java
@@ -0,0 +1,204 @@
+package jp.co.future.uroborosql.dialect;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import jp.co.future.uroborosql.connection.ConnectionContext;
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.enums.ForUpdateType;
+
+/**
+ * Oracle18Dialectの個別実装部分のテストケース
+ *
+ * @author H.Sugimoto
+ *
+ */
+public class Oracle18DialectTest {
+ private final Dialect dialect = new Oracle18Dialect();
+
+ @Test
+ void testAccept18() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-18.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(Oracle18Dialect.class));
+ }
+
+ @Test
+ void testAcceptUnder18() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-12.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle18Dialect.class)));
+ }
+
+ @Test
+ void testAcceptOver18() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-19.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle18Dialect.class)));
+ }
+
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThat(dialect.getSequenceNextValSql("test_sequence"), is("test_sequence.nextval"));
+ }
+
+ @Test
+ void testEscapeLikePattern() {
+ assertThat(dialect.escapeLikePattern(""), is(""));
+ assertThat(dialect.escapeLikePattern(null), nullValue());
+ assertThat(dialect.escapeLikePattern("pattern"), is("pattern"));
+ assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern"));
+ assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%"));
+ assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_"));
+ assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ }
+
+ @Test
+ void testGetEscapeChar() {
+ assertThat(dialect.getEscapeChar(), is('\\'));
+ }
+
+ @Test
+ void testSupports() {
+ assertThat(dialect.supportsBulkInsert(), is(false));
+ assertThat(dialect.supportsLimitClause(), is(true));
+ assertThat(dialect.supportsNullValuesOrdering(), is(true));
+ assertThat(dialect.supportsIdentity(), is(true));
+ assertThat(dialect.supportsSequence(), is(true));
+ assertThat(dialect.isRemoveTerminator(), is(true));
+ assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false));
+ assertThat(dialect.supportsForUpdate(), is(true));
+ assertThat(dialect.supportsForUpdateNoWait(), is(true));
+ assertThat(dialect.supportsForUpdateWait(), is(true));
+ assertThat(dialect.supportsOptimizerHints(), is(true));
+ assertThat(dialect.supportsEntityBulkUpdateOptimisticLock(), is(true));
+ }
+
+ @Test
+ void testGetLimitClause() {
+ assertThat(dialect.getLimitClause(3, 5), is("OFFSET 5 ROWS FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 5), is("OFFSET 5 ROWS" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(3, 0), is("FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 0), is(""));
+ }
+
+ @Test
+ void testAddForUpdateClause() {
+ var sql = new StringBuilder("SELECT * FROM test WHERE 1 = 1 ORDER id").append(System.lineSeparator());
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NORMAL, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NOWAIT, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE NOWAIT"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.WAIT, 10).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE WAIT 10"));
+ }
+
+ @Test
+ void testAddOptimizerHints1() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM test WHERE 1 = 1 ORDER id")
+ .append(System.lineSeparator());
+ List hints = new ArrayList<>();
+ hints.add("INDEX (test test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /*+ INDEX (test test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator()));
+ }
+
+ @Test
+ void testAddOptimizerHints2() {
+ var sql = new StringBuilder("SELECT /* SQL_ID */")
+ .append(System.lineSeparator())
+ .append(" * FROM PUBLIC.TEST_1");
+ List hints = new ArrayList<>();
+ hints.add("INDEX (PUBLIC.TEST_1 test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /* SQL_ID */ /*+ INDEX (PUBLIC.TEST_1 test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM PUBLIC.TEST_1"));
+ }
+
+ @Test
+ void testGetPessimisticLockingErrorCodes() {
+ assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("54", "30006")));
+ }
+
+}
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle19DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle19DialectTest.java
new file mode 100644
index 00000000..16d93d4f
--- /dev/null
+++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle19DialectTest.java
@@ -0,0 +1,204 @@
+package jp.co.future.uroborosql.dialect;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import jp.co.future.uroborosql.connection.ConnectionContext;
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.enums.ForUpdateType;
+
+/**
+ * Oracle19Dialectの個別実装部分のテストケース
+ *
+ * @author H.Sugimoto
+ *
+ */
+public class Oracle19DialectTest {
+ private final Dialect dialect = new Oracle19Dialect();
+
+ @Test
+ void testAccept19() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-19.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(Oracle19Dialect.class));
+ }
+
+ @Test
+ void testAcceptUnder19() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-18.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle19Dialect.class)));
+ }
+
+ @Test
+ void testAcceptOver19() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-21.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle19Dialect.class)));
+ }
+
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThat(dialect.getSequenceNextValSql("test_sequence"), is("test_sequence.nextval"));
+ }
+
+ @Test
+ void testEscapeLikePattern() {
+ assertThat(dialect.escapeLikePattern(""), is(""));
+ assertThat(dialect.escapeLikePattern(null), nullValue());
+ assertThat(dialect.escapeLikePattern("pattern"), is("pattern"));
+ assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern"));
+ assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%"));
+ assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_"));
+ assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ }
+
+ @Test
+ void testGetEscapeChar() {
+ assertThat(dialect.getEscapeChar(), is('\\'));
+ }
+
+ @Test
+ void testSupports() {
+ assertThat(dialect.supportsBulkInsert(), is(false));
+ assertThat(dialect.supportsLimitClause(), is(true));
+ assertThat(dialect.supportsNullValuesOrdering(), is(true));
+ assertThat(dialect.supportsIdentity(), is(true));
+ assertThat(dialect.supportsSequence(), is(true));
+ assertThat(dialect.isRemoveTerminator(), is(true));
+ assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false));
+ assertThat(dialect.supportsForUpdate(), is(true));
+ assertThat(dialect.supportsForUpdateNoWait(), is(true));
+ assertThat(dialect.supportsForUpdateWait(), is(true));
+ assertThat(dialect.supportsOptimizerHints(), is(true));
+ assertThat(dialect.supportsEntityBulkUpdateOptimisticLock(), is(true));
+ }
+
+ @Test
+ void testGetLimitClause() {
+ assertThat(dialect.getLimitClause(3, 5), is("OFFSET 5 ROWS FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 5), is("OFFSET 5 ROWS" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(3, 0), is("FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 0), is(""));
+ }
+
+ @Test
+ void testAddForUpdateClause() {
+ var sql = new StringBuilder("SELECT * FROM test WHERE 1 = 1 ORDER id").append(System.lineSeparator());
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NORMAL, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NOWAIT, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE NOWAIT"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.WAIT, 10).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE WAIT 10"));
+ }
+
+ @Test
+ void testAddOptimizerHints1() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM test WHERE 1 = 1 ORDER id")
+ .append(System.lineSeparator());
+ List hints = new ArrayList<>();
+ hints.add("INDEX (test test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /*+ INDEX (test test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator()));
+ }
+
+ @Test
+ void testAddOptimizerHints2() {
+ var sql = new StringBuilder("SELECT /* SQL_ID */")
+ .append(System.lineSeparator())
+ .append(" * FROM PUBLIC.TEST_1");
+ List hints = new ArrayList<>();
+ hints.add("INDEX (PUBLIC.TEST_1 test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /* SQL_ID */ /*+ INDEX (PUBLIC.TEST_1 test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM PUBLIC.TEST_1"));
+ }
+
+ @Test
+ void testGetPessimisticLockingErrorCodes() {
+ assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("54", "30006")));
+ }
+
+}
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle21DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle21DialectTest.java
new file mode 100644
index 00000000..b8a85485
--- /dev/null
+++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle21DialectTest.java
@@ -0,0 +1,204 @@
+package jp.co.future.uroborosql.dialect;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import jp.co.future.uroborosql.connection.ConnectionContext;
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.enums.ForUpdateType;
+
+/**
+ * Oracle21Dialectの個別実装部分のテストケース
+ *
+ * @author H.Sugimoto
+ *
+ */
+public class Oracle21DialectTest {
+ private final Dialect dialect = new Oracle21Dialect();
+
+ @Test
+ void testAccept21() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-21.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(Oracle21Dialect.class));
+ }
+
+ @Test
+ void testAcceptUnder21() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-19.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle21Dialect.class)));
+ }
+
+ @Test
+ void testAcceptOver21() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-23.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle21Dialect.class)));
+ }
+
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThat(dialect.getSequenceNextValSql("test_sequence"), is("test_sequence.nextval"));
+ }
+
+ @Test
+ void testEscapeLikePattern() {
+ assertThat(dialect.escapeLikePattern(""), is(""));
+ assertThat(dialect.escapeLikePattern(null), nullValue());
+ assertThat(dialect.escapeLikePattern("pattern"), is("pattern"));
+ assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern"));
+ assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%"));
+ assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_"));
+ assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ }
+
+ @Test
+ void testGetEscapeChar() {
+ assertThat(dialect.getEscapeChar(), is('\\'));
+ }
+
+ @Test
+ void testSupports() {
+ assertThat(dialect.supportsBulkInsert(), is(false));
+ assertThat(dialect.supportsLimitClause(), is(true));
+ assertThat(dialect.supportsNullValuesOrdering(), is(true));
+ assertThat(dialect.supportsIdentity(), is(true));
+ assertThat(dialect.supportsSequence(), is(true));
+ assertThat(dialect.isRemoveTerminator(), is(true));
+ assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false));
+ assertThat(dialect.supportsForUpdate(), is(true));
+ assertThat(dialect.supportsForUpdateNoWait(), is(true));
+ assertThat(dialect.supportsForUpdateWait(), is(true));
+ assertThat(dialect.supportsOptimizerHints(), is(true));
+ assertThat(dialect.supportsEntityBulkUpdateOptimisticLock(), is(true));
+ }
+
+ @Test
+ void testGetLimitClause() {
+ assertThat(dialect.getLimitClause(3, 5), is("OFFSET 5 ROWS FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 5), is("OFFSET 5 ROWS" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(3, 0), is("FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 0), is(""));
+ }
+
+ @Test
+ void testAddForUpdateClause() {
+ var sql = new StringBuilder("SELECT * FROM test WHERE 1 = 1 ORDER id").append(System.lineSeparator());
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NORMAL, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NOWAIT, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE NOWAIT"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.WAIT, 10).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE WAIT 10"));
+ }
+
+ @Test
+ void testAddOptimizerHints1() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM test WHERE 1 = 1 ORDER id")
+ .append(System.lineSeparator());
+ List hints = new ArrayList<>();
+ hints.add("INDEX (test test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /*+ INDEX (test test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator()));
+ }
+
+ @Test
+ void testAddOptimizerHints2() {
+ var sql = new StringBuilder("SELECT /* SQL_ID */")
+ .append(System.lineSeparator())
+ .append(" * FROM PUBLIC.TEST_1");
+ List hints = new ArrayList<>();
+ hints.add("INDEX (PUBLIC.TEST_1 test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /* SQL_ID */ /*+ INDEX (PUBLIC.TEST_1 test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM PUBLIC.TEST_1"));
+ }
+
+ @Test
+ void testGetPessimisticLockingErrorCodes() {
+ assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("54", "30006")));
+ }
+
+}
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle23DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle23DialectTest.java
new file mode 100644
index 00000000..c8afbdb5
--- /dev/null
+++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle23DialectTest.java
@@ -0,0 +1,204 @@
+package jp.co.future.uroborosql.dialect;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import jp.co.future.uroborosql.connection.ConnectionContext;
+import jp.co.future.uroborosql.connection.ConnectionSupplier;
+import jp.co.future.uroborosql.enums.ForUpdateType;
+
+/**
+ * Oracle23Dialectの個別実装部分のテストケース
+ *
+ * @author H.Sugimoto
+ *
+ */
+public class Oracle23DialectTest {
+ private final Dialect dialect = new Oracle23Dialect();
+
+ @Test
+ void testAccept23() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-23.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(Oracle23Dialect.class));
+ }
+
+ @Test
+ void testAcceptUnder23() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-21.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, not(instanceOf(Oracle23Dialect.class)));
+ }
+
+ @Test
+ void testAcceptOver23() {
+ ConnectionSupplier supplier = new ConnectionSupplier() {
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public Connection getConnection(final ConnectionContext ctx) {
+ return null;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return "Oracle-24.1";
+ }
+ };
+
+ var dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false)
+ .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new);
+
+ assertThat(dialect, instanceOf(Oracle23Dialect.class));
+ }
+
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThat(dialect.getSequenceNextValSql("test_sequence"), is("test_sequence.nextval"));
+ }
+
+ @Test
+ void testEscapeLikePattern() {
+ assertThat(dialect.escapeLikePattern(""), is(""));
+ assertThat(dialect.escapeLikePattern(null), nullValue());
+ assertThat(dialect.escapeLikePattern("pattern"), is("pattern"));
+ assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern"));
+ assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%"));
+ assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_"));
+ assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern"));
+ assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern"));
+ assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern"));
+ }
+
+ @Test
+ void testGetEscapeChar() {
+ assertThat(dialect.getEscapeChar(), is('\\'));
+ }
+
+ @Test
+ void testSupports() {
+ assertThat(dialect.supportsBulkInsert(), is(true));
+ assertThat(dialect.supportsLimitClause(), is(true));
+ assertThat(dialect.supportsNullValuesOrdering(), is(true));
+ assertThat(dialect.supportsIdentity(), is(true));
+ assertThat(dialect.supportsSequence(), is(true));
+ assertThat(dialect.isRemoveTerminator(), is(true));
+ assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false));
+ assertThat(dialect.supportsForUpdate(), is(true));
+ assertThat(dialect.supportsForUpdateNoWait(), is(true));
+ assertThat(dialect.supportsForUpdateWait(), is(true));
+ assertThat(dialect.supportsOptimizerHints(), is(true));
+ assertThat(dialect.supportsEntityBulkUpdateOptimisticLock(), is(true));
+ }
+
+ @Test
+ void testGetLimitClause() {
+ assertThat(dialect.getLimitClause(3, 5), is("OFFSET 5 ROWS FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 5), is("OFFSET 5 ROWS" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(3, 0), is("FETCH FIRST 3 ROWS ONLY" + System.lineSeparator()));
+ assertThat(dialect.getLimitClause(0, 0), is(""));
+ }
+
+ @Test
+ void testAddForUpdateClause() {
+ var sql = new StringBuilder("SELECT * FROM test WHERE 1 = 1 ORDER id").append(System.lineSeparator());
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NORMAL, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.NOWAIT, -1).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE NOWAIT"));
+ assertThat(dialect.addForUpdateClause(sql, ForUpdateType.WAIT, 10).toString(),
+ is("SELECT * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator() + "FOR UPDATE WAIT 10"));
+ }
+
+ @Test
+ void testAddOptimizerHints1() {
+ var sql = new StringBuilder("SELECT")
+ .append(System.lineSeparator())
+ .append(" * FROM test WHERE 1 = 1 ORDER id")
+ .append(System.lineSeparator());
+ List hints = new ArrayList<>();
+ hints.add("INDEX (test test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /*+ INDEX (test test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM test WHERE 1 = 1 ORDER id" + System.lineSeparator()));
+ }
+
+ @Test
+ void testAddOptimizerHints2() {
+ var sql = new StringBuilder("SELECT /* SQL_ID */")
+ .append(System.lineSeparator())
+ .append(" * FROM PUBLIC.TEST_1");
+ List hints = new ArrayList<>();
+ hints.add("INDEX (PUBLIC.TEST_1 test_ix)");
+ hints.add("USE_NL");
+
+ assertThat(dialect.addOptimizerHints(sql, hints).toString(),
+ is("SELECT /* SQL_ID */ /*+ INDEX (PUBLIC.TEST_1 test_ix) USE_NL */" + System.lineSeparator()
+ + " * FROM PUBLIC.TEST_1"));
+ }
+
+ @Test
+ void testGetPessimisticLockingErrorCodes() {
+ assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("54", "30006")));
+ }
+
+}
diff --git a/src/test/java/jp/co/future/uroborosql/dialect/PostgresqlDialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/PostgresqlDialectTest.java
index 867578e0..1edbd63b 100644
--- a/src/test/java/jp/co/future/uroborosql/dialect/PostgresqlDialectTest.java
+++ b/src/test/java/jp/co/future/uroborosql/dialect/PostgresqlDialectTest.java
@@ -177,4 +177,9 @@ void testGetPessimisticLockingErrorCodes() {
assertThat(dialect.getPessimisticLockingErrorCodes(), is(containsInAnyOrder("55P03")));
}
+ @Test
+ void testGetSequenceNextValSql() {
+ assertThat(dialect.getSequenceNextValSql("test_sequence"), is("nextval('test_sequence')"));
+ }
+
}