diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java index 90fb451e20..f185ee4939 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java @@ -321,7 +321,7 @@ public class DBDictionary public int maxEmbeddedBlobSize = -1; public int maxEmbeddedClobSize = -1; public int inClauseLimit = -1; - + /** * Attention, while this is named datePrecision it actually only get used for Timestamp handling! * @see StateManagerImpl#roundTimestamp(Timestamp, int) @@ -502,10 +502,10 @@ public enum DateMillisecondBehaviors { DROP, ROUND, RETAIN } private String conversionKey = null; public boolean supportsUuidType = false; - + public boolean supportsUnsizedCharOnCast = true; - - public String integerCastTypeName = integerTypeName; + + public String integerCastTypeName = integerTypeName; // Naming utility and naming rules private DBIdentifierUtil namingUtil = null; @@ -638,6 +638,10 @@ protected void configureNamingRules() { DBIdentifierRule columnNamingRule = new ColumnIdentifierRule(invalidColumnWordSet); namingRules.put(columnNamingRule.getName(), columnNamingRule); + // restoring default "empty" cfg + IdentifierRule rule = Normalizer.getNamingConfiguration().getDefaultIdentifierRule(); + rule.setDelimitReservedWords(false); + rule.setReservedWords(Set.of()); } ////////////////////// @@ -2063,7 +2067,7 @@ public String getTypeName(Column col) { return appendSize(col, autoAssignTypeName); if (col.getJavaType() == JavaTypes.UUID_OBJ) { - if (supportsUuidType) + if (supportsUuidType) return appendSize(col, uuidTypeName); else { return appendSize(col, getTypeName(Types.VARCHAR)); @@ -3270,7 +3274,7 @@ public void substring(SQLBuffer buf, FilterValue str, FilterValue start, } buf.append(")"); } - + public void replace(SQLBuffer buf, FilterValue from, FilterValue subs, FilterValue replacement) { buf.append(replaceFunctionName).append("("); from.appendTo(buf); @@ -3280,7 +3284,7 @@ public void replace(SQLBuffer buf, FilterValue from, FilterValue subs, FilterVal replacement.appendTo(buf); buf.append(")"); } - + public void left(SQLBuffer buf, FilterValue str, FilterValue length) { buf.append(leftFunctionName).append("("); str.appendTo(buf); @@ -5298,7 +5302,9 @@ public void endConfiguration() { selectWordSet.addAll(Arrays.asList(StringUtil.split(selectWords.toUpperCase(Locale.ENGLISH), ",", 0))); if (invalidColumnWordSet.isEmpty()) { - invalidColumnWordSet.addAll(loadFromResource("sql-invalid-column-names.rsrc")); + Collection invalidColumns = loadFromResource("sql-invalid-column-names.rsrc"); + invalidColumnWordSet.addAll(invalidColumns); + namingRules.get(DBIdentifierType.COLUMN.name()).setReservedWords(invalidColumns); } // initialize the error codes @@ -5578,11 +5584,10 @@ public void closeDataSource(DataSource dataSource) { } /** - * Used by some mappings to represent data that has already been - * serialized so that we don't have to serialize multiple times. - */ - public record SerializedData(byte[] bytes) { - + * Used by some mappings to represent data that has already been + * serialized so that we don't have to serialize multiple times. + */ + public record SerializedData(byte[] bytes) { } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java index 8d8676f1e0..8a2398774f 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java @@ -31,6 +31,7 @@ import java.util.Set; import org.apache.openjpa.jdbc.identifier.DBIdentifier; +import org.apache.openjpa.jdbc.identifier.Normalizer; import org.apache.openjpa.jdbc.identifier.DBIdentifier.DBIdentifierType; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCStore; @@ -41,6 +42,7 @@ import org.apache.openjpa.jdbc.schema.Index; import org.apache.openjpa.jdbc.schema.PrimaryKey; import org.apache.openjpa.jdbc.schema.Table; +import org.apache.openjpa.lib.identifier.IdentifierRule; import org.apache.openjpa.lib.util.StringUtil; import org.apache.openjpa.util.ExceptionInfo; import org.apache.openjpa.util.StoreException; @@ -129,7 +131,7 @@ public MySQLDictionary() { "AUTO_INCREMENT", "BINARY", "BLOB", "CHANGE", "ENUM", "INFILE", "INT1", "INT2", "INT4", "FLOAT1", "FLOAT2", "FLOAT4", "LOAD", "MEDIUMINT", "OUTFILE", "REPLACE", "STARTING", "TEXT", "UNSIGNED", - "ZEROFILL", "INDEX", + "ZEROFILL", "INDEX", "LIBRARY" })); // reservedWordSet subset that CANNOT be used as valid column names @@ -271,6 +273,14 @@ private static int[] getMajorMinorVersions(String versionStr) return new int[]{maj, min}; } + @Override + protected void configureNamingRules() { + super.configureNamingRules(); + IdentifierRule rule = Normalizer.getNamingConfiguration().getDefaultIdentifierRule(); + rule.setDelimitReservedWords(true); + rule.setReservedWords(reservedWordSet); + } + @Override public String[] getCreateTableSQL(Table table) { String[] sql = super.getCreateTableSQL(table); @@ -477,8 +487,8 @@ protected int matchErrorState(Map> errorStates, SQLException if (state == ExceptionInfo.GENERAL && ex.getErrorCode() == 0 && ex.getSQLState() == null) { // look at the nested MySQL exception for more details SQLException sqle = ex.getNextException(); - if (sqle != null - && (sqle.toString().startsWith("com.mysql.jdbc.exceptions.MySQLTimeoutException") || + if (sqle != null + && (sqle.toString().startsWith("com.mysql.jdbc.exceptions.MySQLTimeoutException") || sqle.toString().startsWith("com.mysql.cj.jdbc.exceptions.MySQLTimeoutException"))) { if (conf != null && conf.getLockTimeout() != -1) { state = StoreException.LOCK; diff --git a/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestSchemaTool.java b/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestSchemaTool.java index eaf4cd913c..bb2f4aa7ee 100644 --- a/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestSchemaTool.java +++ b/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestSchemaTool.java @@ -19,10 +19,12 @@ package org.apache.openjpa.jdbc.meta; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl; @@ -39,20 +41,20 @@ public class TestSchemaTool { @Parameters(name = "{index}: {0} -> {1}") public static Collection data() { return Arrays.asList(new Object[][] { - {"", 0}, - {" ", 0}, - {"org/apache/openjpa/jdbc/meta/testScript1", 0}, - {"org/apache/openjpa/jdbc/meta/testScript2", 1}, - {"org/apache/openjpa/jdbc/meta/testScript3", 1}, - {"org/apache/openjpa/jdbc/meta/testScript4", 0}, - {"org/apache/openjpa/jdbc/meta/testScriptMulti1", 1}, - {"org/apache/openjpa/jdbc/meta/testScriptMulti2", 0}, + {"", List.of()}, + {" ", List.of()}, + {"org/apache/openjpa/jdbc/meta/testScript1", List.of()}, + {"org/apache/openjpa/jdbc/meta/testScript2", List.of("SELECT * FROM Customers WHERE Country = 'Germany'")}, + {"org/apache/openjpa/jdbc/meta/testScript3", List.of("SELECT * FROM Customers")}, + {"org/apache/openjpa/jdbc/meta/testScript4", List.of()}, + {"org/apache/openjpa/jdbc/meta/testScriptMulti1", List.of("SELECT * FROM MyTable")}, + {"org/apache/openjpa/jdbc/meta/testScriptMulti2", List.of()}, }); } @Parameter(0) public String sqlScript; @Parameter(1) - public Integer resultingLines; + public List expected; @Test public void testExecuteScript() throws Exception { @@ -75,6 +77,12 @@ protected boolean executeSQL(String[] sql) { }; tool.setScriptToExecute(sqlScript); tool.run(); - assertEquals(resultingLines.intValue(), sqlToRun.size()); + if (expected.size() != sqlToRun.size()) { + fail("Expected list wasn't found: \r\n expected" + expected + + "\r\n actual: \r\n" + sqlToRun); + } + for (int i = 0; i < expected.size(); ++i) { + assertEquals(expected.get(i), sqlToRun.get(i)); + } } } diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/identifier/IdentifierRule.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/identifier/IdentifierRule.java index a9c90d2509..1d28c6058c 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/identifier/IdentifierRule.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/identifier/IdentifierRule.java @@ -18,8 +18,11 @@ */ package org.apache.openjpa.lib.identifier; +import java.util.Collection; import java.util.HashSet; +import java.util.Locale; import java.util.Set; +import java.util.stream.Collectors; import org.apache.openjpa.lib.util.StringUtil; @@ -122,8 +125,10 @@ public boolean isOnlyLettersDigitsUnderscores() { return _onlyLettersDigitsUnderscores; } - public void setReservedWords(Set reservedWords) { - _reservedWords = reservedWords; + public void setReservedWords(Collection reservedWords) { + _reservedWords = reservedWords.stream() + .map(w -> w.toUpperCase(Locale.ENGLISH)) + .collect(Collectors.toSet()); } public Set getReservedWords() { @@ -202,6 +207,6 @@ public boolean requiresDelimiters(String identifier) { } public boolean isReservedWord(String identifier) { - return _reservedWords.contains(identifier); + return _reservedWords.contains(identifier.toUpperCase(Locale.ENGLISH)); } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestSnakeCaseDDL.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestSnakeCaseDDL.java index 76c7ab63c4..f6ae11868d 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestSnakeCaseDDL.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestSnakeCaseDDL.java @@ -48,7 +48,7 @@ import static org.junit.Assert.assertTrue; public class TestSnakeCaseDDL { - + private static final Logger logger = Logger.getLogger(TestSnakeCaseDDL.class.getCanonicalName()); @Test @@ -82,8 +82,9 @@ public void ddlInSnakeCase() throws SQLException { .getTables(null, null, "%", null)) { while (tables.next()) { final String table = tables.getString(3); - if (table.toUpperCase(Locale.ROOT).startsWith("SNAKE")) { - createdTables.put(table.toUpperCase(Locale.ROOT), table); + final String upper = table.toUpperCase(Locale.ENGLISH); + if (upper.startsWith("SNAKE")) { + createdTables.put(upper, table); } } } @@ -132,7 +133,7 @@ public void ddlInSnakeCase() throws SQLException { em.close(); } } - final String tableName = createdTables.get("SnakeCaseDDLMy1Entity".toUpperCase(Locale.ROOT)); + final String tableName = createdTables.get("SnakeCaseDDLMy1Entity".toUpperCase(Locale.ENGLISH)); try (final Connection connection = ds.getConnection(); final Statement statement = connection.createStatement(); final ResultSet rs = statement.executeQuery("select foo_bar, this_field from \"" + tableName + "\"")) { diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/AbstractCriteriaTestCase.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/AbstractCriteriaTestCase.java index 8db426de4a..85b35dd7cd 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/AbstractCriteriaTestCase.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/AbstractCriteriaTestCase.java @@ -53,7 +53,7 @@ * @version $Rev$ $Date$ */ public abstract class AbstractCriteriaTestCase extends TestCase { - + private static final Logger logger = Logger.getLogger(AbstractCriteriaTestCase.class.getCanonicalName()); protected abstract SQLAuditor getAuditor(); @@ -156,6 +156,13 @@ void assertEquivalence(QueryDecorator decorator, CriteriaQuery c, String jpql executeAndCompareSQL(jpql, cQ, jQ, expectedSQL); } + protected boolean same(String expected, String sql) { + return sql.equalsIgnoreCase(expected) || + sql.replace(dict.getLeadingDelimiter(), "") + .replace(dict.getTrailingDelimiter(), "") + .equalsIgnoreCase(expected); + } + /** * Execute the two given queries. The first query originated from a JPQL string must be well-formed. The second * query originated from a Criteria is being tested. @@ -194,19 +201,20 @@ void executeAndCompareSQL(String jpql, Query cQ, Query jQ, String expectedSQL) { return; for (int i = 0; i < jSQL.size(); i++) { - if (!jSQL.get(i).equalsIgnoreCase(cSQL.get(i))) { + boolean eq = same(cSQL.get(i), jSQL.get(i)); + if (!eq) { printSQL("Target SQL for JPQL", jSQL); printSQL("Target SQL for CriteriaQuery", cSQL); - assertTrue(i + "-th SQL for JPQL and CriteriaQuery for " + jpql + " is different\r\n" + - "JPQL = [" + jSQL.get(i) + "]\r\n" + - "CSQL = [" + cSQL.get(i) + "]\r\n", - jSQL.get(i).equalsIgnoreCase(cSQL.get(i))); } + assertTrue(i + "-th SQL for JPQL and CriteriaQuery for " + jpql + " is different\r\n" + + "JPQL = [" + jSQL.get(i) + "]\r\n" + + "CSQL = [" + cSQL.get(i) + "]\r\n", + eq); } if (expectedSQL != null) { assertTrue("SQL for JPQL " + jpql + " is different than expecetd " + expectedSQL, - jSQL.get(0).equalsIgnoreCase(expectedSQL)); + same(expectedSQL, jSQL.get(0))); } } @@ -227,12 +235,12 @@ void executeAndCompareSQL(String jpql, String expectedSQL) { return; for (int i = 0; i < jSQL.size(); i++) { - if (!jSQL.get(i).equalsIgnoreCase(expectedSQL)) { + boolean eq = same(expectedSQL, jSQL.get(i)); + if (!eq) { printSQL("SQL for JPQL", jSQL.get(i)); printSQL("Expected SQL", expectedSQL); - assertTrue(i + "-th SQL for JPQL: " + jSQL.get(i) + " are different than Expected SQL " + expectedSQL, - expectedSQL.equalsIgnoreCase(jSQL.get(i))); } + assertTrue(i + "-th SQL for JPQL: " + jSQL.get(i) + " are different than Expected SQL " + expectedSQL, eq); } } @@ -246,18 +254,20 @@ void executeAndCompareSQL(Query jQ, String expectedSQL) { fail(w.toString()); } - if (!(dict instanceof DerbyDictionary || dict instanceof MySQLDictionary || dict instanceof MariaDBDictionary)) + if (!(dict instanceof DerbyDictionary || dict instanceof MySQLDictionary || dict instanceof MariaDBDictionary)) { return; + } String jSql = jSQL.get(0).trim(); - if (jSql.indexOf("optimize for 1 row") != -1) + if (jSql.indexOf("optimize for 1 row") != -1) { jSql = jSql.substring(0, jSql.indexOf("optimize for 1 row")).trim(); + } - if (!jSql.equalsIgnoreCase(expectedSQL)) { + boolean eq = same(expectedSQL, jSql); + if (!eq) { printSQL("SQL for JPQL", jSql); - assertTrue("SQL for JPQL " + jSql + " is different than expecetd " + expectedSQL, - expectedSQL.equalsIgnoreCase(jSql)); } + assertTrue("SQL for JPQL " + jSql + " is different than expecetd " + expectedSQL, eq); } void executeExpectFail(CriteriaQuery c, String jpql) { diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestFKColumnNames.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestFKColumnNames.java index 2272e9dcd9..b76318e63e 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestFKColumnNames.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/TestFKColumnNames.java @@ -20,7 +20,12 @@ import jakarta.persistence.Persistence; +import java.util.Locale; + +import org.apache.openjpa.jdbc.identifier.Normalizer; import org.apache.openjpa.jdbc.meta.MappingRepository; +import org.apache.openjpa.jdbc.schema.Column; +import org.apache.openjpa.lib.identifier.IdentifierConfiguration; import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase; @@ -28,7 +33,13 @@ * Testcase that verifies the names for Foreign Key columns is as expected. */ public class TestFKColumnNames extends AbstractPersistenceTestCase { - + private String getName(Column col) { + IdentifierConfiguration cfg = Normalizer.getNamingConfiguration(); + return col.getIdentifier().getName() + .replace(cfg.getLeadingDelimiter(), "") + .replace(cfg.getTrailingDelimiter(), "") + .toUpperCase(Locale.ENGLISH); + } /** *

@@ -48,11 +59,11 @@ public void testSQLKeywords() { (MappingRepository) emf.getConfiguration() .getMetaDataRepositoryInstance(); - assertEquals("SELECT_ID", repos.getMapping(FKColumnNamesInner1Entity.class, null, true) - .getFieldMapping("select").getColumns()[0].getName()); + assertEquals("SELECT_ID", getName(repos.getMapping(FKColumnNamesInner1Entity.class, null, true) + .getFieldMapping("select").getColumns()[0])); - assertEquals("FROM_ID", repos.getMapping(FKColumnNamesInner2Entity.class, null, true) - .getFieldMapping("from").getColumns()[0].getName()); + assertEquals("FROM_ID", getName(repos.getMapping(FKColumnNamesInner2Entity.class, null, true) + .getFieldMapping("from").getColumns()[0])); closeEMF(emf); } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java index 778d50daf2..4186ade2c9 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.List; +import org.apache.openjpa.jdbc.sql.DBDictionary; import org.apache.openjpa.lib.jdbc.JDBCListener; /** @@ -57,9 +58,17 @@ public void tearDown() throws Exception { * @param sqlExp the SQL expression. E.g., "SELECT FOO .*" */ public void assertSQL(String sqlExp) { + DBDictionary dict = getDBDictionary(); for (String statement : sql) { - if (statement.matches(sqlExp)) + if (statement.matches(sqlExp)) { + return; + } + String noDelims = statement + .replace(dict.getLeadingDelimiter(), "") + .replace(dict.getTrailingDelimiter(), ""); + if (noDelims.matches(sqlExp)) { return; + } } fail("Expected regular expression\r\n <" + sqlExp diff --git a/openjpa-project/checkstyle.xml b/openjpa-project/checkstyle.xml index d59aa17412..52c58c106f 100644 --- a/openjpa-project/checkstyle.xml +++ b/openjpa-project/checkstyle.xml @@ -10,9 +10,8 @@ OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - + "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" + "https://checkstyle.org/dtds/configuration_1_3.dtd"> diff --git a/openjpa-project/suppressions.xml b/openjpa-project/suppressions.xml index e7541efb42..69a5cc9685 100644 --- a/openjpa-project/suppressions.xml +++ b/openjpa-project/suppressions.xml @@ -1,9 +1,8 @@ - + "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" + "https://checkstyle.org/dtds/suppressions_1_2.dtd"> diff --git a/openjpa-tools/openjpa-maven-plugin/src/site/site.xml b/openjpa-tools/openjpa-maven-plugin/src/site/site.xml index e87e069e1d..15abe84224 100644 --- a/openjpa-tools/openjpa-maven-plugin/src/site/site.xml +++ b/openjpa-tools/openjpa-maven-plugin/src/site/site.xml @@ -16,7 +16,9 @@ | --> - +

@@ -30,4 +32,4 @@ - \ No newline at end of file + diff --git a/src/site/site.xml b/src/site/site.xml index be9fc25596..a0e1c3269f 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -17,9 +17,12 @@ specific language governing permissions and limitations under the License. --> - - - OpenJPA + + + OpenJPA Logo @@ -30,8 +33,7 @@ - + @@ -45,4 +47,4 @@ maven-fluido-skin 2.1.0 - +