Skip to content

Commit

Permalink
fix(db): ensure case-sensitive DB collations work (#4542)
Browse files Browse the repository at this point in the history
Related to #4525
  • Loading branch information
mboskamp authored Aug 23, 2024
1 parent 95ad993 commit c28764a
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@
<!-- HISTORIC ACTIVITY INSTANCE SELECT -->

<select id="selectHistoricActivityInstance" resultMap="historicActivityInstanceResultMap">
select * from ${prefix}ACT_HI_ACTINST where Id_ = #{id}
select * from ${prefix}ACT_HI_ACTINST where ID_ = #{id}
</select>

<select id="selectHistoricActivityInstancesByQueryCriteria" parameterType="org.camunda.bpm.engine.impl.HistoricActivityInstanceQueryImpl" resultMap="historicActivityInstanceResultMap">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
<!-- HISTORIC CASE ACTIVITY INSTANCE SELECT -->

<select id="selectHistoricCaseActivityInstance" resultMap="historicCaseActivityInstanceResultMap">
select * from ${prefix}ACT_HI_CASEACTINST where Id_ = #{id}
select * from ${prefix}ACT_HI_CASEACTINST where ID_ = #{id}
</select>

<select id="selectHistoricCaseActivityInstancesByQueryCriteria" parameterType="org.camunda.bpm.engine.impl.HistoricCaseActivityInstanceQueryImpl" resultMap="historicCaseActivityInstanceResultMap">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.engine.test.persistence;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.junit.Test;

public class DatabaseNamingConsistencyTest {

public static String COLUMN_NAME_REGEX = "([a-zA-Z_]*(?=[a-z]+)[a-zA-Z_]+_)[,\\s]";
public static String[] SCANNED_FOLDERS = {
"org/camunda/bpm/engine/impl/mapping/entity/",
"org/camunda/bpm/engine/db/create", "org/camunda/bpm/engine/db/drop",
"org/camunda/bpm/engine/db/liquibase/baseline" };

@Test
public void shouldNotFindLowercaseDbColumnNamesInMappings() {
// given the rule that all DB column names are created in uppercase

// when scanning all mapping files for lowercase column names
StringBuilder errorMessageBuilder = new StringBuilder();
Pattern pattern = Pattern.compile(COLUMN_NAME_REGEX);
try {
for (String scannedFolder : SCANNED_FOLDERS) {
URL resource = getClass().getClassLoader().getResource(scannedFolder);
if (resource == null) {
throw new IOException("Could not find path: " + scannedFolder);
}
File folder = new File(resource.getFile());
File[] filesInFolder = folder.listFiles();
for (File file : filesInFolder) {
AtomicInteger lineNumber = new AtomicInteger(0);
try (Stream<String> lines = Files.lines(file.toPath())) {
lines.forEach(line -> {
lineNumber.getAndIncrement();
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
errorMessageBuilder.append(
"Found illegal lowercase column name " + matcher.group(1) + " in SQL " + file + " at line "
+ lineNumber + ". All SQL column names should be uppercase.\n");
}
});
}
}
}
} catch (IOException e) {
fail("Unable to find test resource for test " + getClass().getName() + "\n" + e.getMessage());
}
// then don't expect any results
String errorMessage = errorMessageBuilder.toString();
if (!errorMessage.isEmpty()) {
fail(errorMessage);
}
}

@Test
public void shouldFindLowercaseDbColumnNamesInTestStrings() {
// given
String[] testStringsIncorrect = { "alter table ACT_RU_TASK add column TASK_sTATE_ varchar(64);",
"${queryType} E.BUSINESS_kEY_ = #{query.processInstanceBusinessKey}", "and RES.AssIGNEE_ is null" };
String[] testStringsCorrect = { "alter table ACT_RU_TASK add column TASK_STATE_ varchar(64);",
"${queryType} E.BUSINESS_KEY_ = #{query.processInstanceBusinessKey}", "and RES.ASSIGNEE_ is null" };
String[] testStrings = Stream.concat(Arrays.stream(testStringsIncorrect), Arrays.stream(testStringsCorrect))
.toArray(String[]::new);

Pattern pattern = Pattern.compile(COLUMN_NAME_REGEX);
List<String> errors = new ArrayList<>();

// when
for (String testString : testStrings) {
Matcher matcher = pattern.matcher(testString);
if (matcher.find()) {
errors.add(testString);
}
}

// then
assertThat(errors).containsAll(Arrays.asList(testStringsIncorrect));
assertThat(errors).doesNotContainAnyElementsOf(Arrays.asList(testStringsCorrect));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
select
PROCDEF.KEY_
, PROCDEF.TENANT_ID_
, max(PROCDEF.version_) as LATEST_VERSION_
, max(PROCDEF.VERSION_) as LATEST_VERSION_
, ${dbSpecificIfNullFunction}(sum(INSTANCE.INSTANCE_COUNT_), 0) as INSTANCE_COUNT_
, ${dbSpecificIfNullFunction}(sum(INC.INCIDENT_COUNT_), 0) as INCIDENT_COUNT_
<!-- Join process definitions with data about running instances and failed jobs -->
Expand Down Expand Up @@ -119,8 +119,8 @@
group by PROCDEF.KEY_, PROCDEF.TENANT_ID_
) GROUPED
<!-- join on key, tenantId and latest version -->
on GROUPED.key_ = RES.key_ and GROUPED.latest_version_ = RES.version_ and
(GROUPED.tenant_id_ = RES.tenant_id_ or (GROUPED.tenant_id_ is null and RES.tenant_id_ is null))
on GROUPED.KEY_ = RES.KEY_ and GROUPED.LATEST_VERSION_ = RES.VERSION_ and
(GROUPED.TENANT_ID_ = RES.TENANT_ID_ or (GROUPED.TENANT_ID_ is null and RES.TENANT_ID_ is null))
) RES

<if test="authCheck.shouldPerformAuthorizatioCheck &amp;&amp; !authCheck.revokeAuthorizationCheckEnabled &amp;&amp; authCheck.authUserId != null">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.webapp.impl.engine;

import static org.assertj.core.api.Assertions.fail;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.junit.Test;

public class WebappsDatabaseNamingConsistencyTest {

public static String COLUMN_NAME_REGEX = "([a-zA-Z_]*(?=[a-z]+)[a-zA-Z_]+_)[,\\s]";
public static String[] SCANNED_FOLDERS = { "org/camunda/bpm/cockpit/plugin/base/queries",
"org/camunda/bpm/admin/plugin/base/queries" };

@Test
public void shouldNotFindLowercaseDbColumnNamesInMappings() {
// given the rule that all DB column names are created in uppercase

// when scanning all mapping files for lowercase column names
StringBuilder errorMessageBuilder = new StringBuilder();
Pattern pattern = Pattern.compile(COLUMN_NAME_REGEX);
try {
for (String scannedFolder : SCANNED_FOLDERS) {
URL resource = getClass().getClassLoader().getResource(scannedFolder);
if (resource == null) {
throw new IOException("Could not find path: " + scannedFolder);
}
File folder = new File(resource.getFile());
File[] filesInFolder = folder.listFiles();
for (File file : filesInFolder) {
AtomicInteger lineNumber = new AtomicInteger(0);
try (Stream<String> lines = Files.lines(file.toPath())) {
lines.forEach(line -> {
lineNumber.getAndIncrement();
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
errorMessageBuilder.append(
"Found illegal lowercase column name " + matcher.group(1) + " in SQL " + file + " at line "
+ lineNumber + ". All SQL column names should be uppercase.\n");
}
});
}
}
}
} catch (IOException e) {
fail("Unable to find test resource for test " + getClass().getName() + "\n" + e.getMessage());
}
// then don't expect any results
String errorMessage = errorMessageBuilder.toString();
if (!errorMessage.isEmpty()) {
fail(errorMessage);
}
}
}

0 comments on commit c28764a

Please sign in to comment.