浏览代码

SONAR-19612 Change index constraint for postgresql 15- and add support for "NULLS NOT DISTINCT" for supported vendor

tags/10.3.0.82913
Léo Geoffroy 7 个月前
父节点
当前提交
70a3f8f8fa
共有 21 个文件被更改,包括 265 次插入112 次删除
  1. 5
    0
      server/sonar-db-core/src/main/java/org/sonar/db/dialect/AbstractDialect.java
  2. 6
    1
      server/sonar-db-core/src/main/java/org/sonar/db/dialect/Dialect.java
  3. 5
    0
      server/sonar-db-core/src/main/java/org/sonar/db/dialect/H2.java
  4. 9
    0
      server/sonar-db-core/src/main/java/org/sonar/db/dialect/PostgreSql.java
  5. 5
    0
      server/sonar-db-core/src/test/java/org/sonar/db/dialect/H2Test.java
  6. 24
    3
      server/sonar-db-core/src/test/java/org/sonar/db/dialect/PostgreSqlTest.java
  7. 50
    50
      server/sonar-db-dao/src/schema/schema-sq.ddl
  8. 52
    4
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/CreateIndexBuilder.java
  9. 1
    1
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/CreateIndexOnColumn.java
  10. 1
    1
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/CreateIndexOnColumns.java
  11. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v00/CreateInitialSchema.java
  12. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/CreateUniqueIndexForScimGroupsUuid.java
  13. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateIndexForEmailOnUsersTable.java
  14. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateIndexForScmAccountOnScmAccountsTable.java
  15. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateIndexOnExternalIdAndIdentityOnExternalGroupsTable.java
  16. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateUniqueIndexForReportSchedulesTable.java
  17. 3
    3
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateUniqueIndexForReportSubscriptionsTable.java
  18. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateUniqueConstraintOnIssuesImpacts.java
  19. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateUniqueConstraintOnRulesDefaultImpacts.java
  20. 84
    29
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/sql/CreateIndexBuilderTest.java
  21. 4
    4
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/GroupPermissionChangerIT.java

+ 5
- 0
server/sonar-db-core/src/main/java/org/sonar/db/dialect/AbstractDialect.java 查看文件

@@ -82,6 +82,11 @@ abstract class AbstractDialect implements Dialect {
return false;
}

@Override
public boolean supportsNullNotDistinct() {
return false;
}

Version checkDbVersion(DatabaseMetaData metaData, Version minSupported) throws SQLException {
int major = metaData.getDatabaseMajorVersion();
int minor = metaData.getDatabaseMinorVersion();

+ 6
- 1
server/sonar-db-core/src/main/java/org/sonar/db/dialect/Dialect.java 查看文件

@@ -62,12 +62,17 @@ public interface Dialect {

boolean supportsUpsert();

/**
* Indicates whether the dialect supports the NULLS NOT DISTINCT clause in unique indexes
*/
boolean supportsNullNotDistinct();

/**
* This method is called when connecting for the first
* time to the database.
*
* @throws MessageException when validation error must be displayed to user
* @throws SQLException in case of error to run the validations
* @throws SQLException in case of error to run the validations
*/
void init(DatabaseMetaData metaData) throws SQLException;
}

+ 5
- 0
server/sonar-db-core/src/main/java/org/sonar/db/dialect/H2.java 查看文件

@@ -41,6 +41,11 @@ public class H2 extends AbstractDialect {
return false;
}

@Override
public boolean supportsNullNotDistinct() {
return true;
}

@Override
public void init(DatabaseMetaData metaData) {
LoggerFactory.getLogger(getClass()).warn("H2 database should be used for evaluation purpose only.");

+ 9
- 0
server/sonar-db-core/src/main/java/org/sonar/db/dialect/PostgreSql.java 查看文件

@@ -33,9 +33,11 @@ public class PostgreSql extends AbstractDialect {
static final List<String> INIT_STATEMENTS = List.of("SET standard_conforming_strings=on", "SET backslash_quote=off");
private static final Version MIN_SUPPORTED_VERSION = Version.create(9, 3, 0);
private static final Version MIN_UPSERT_VERSION = Version.create(9, 5, 0);
private static final Version MIN_NULL_NOT_DISTINCT_VERSION = Version.create(15, 0, 0);

private boolean initialized = false;
private boolean supportsUpsert = false;
private boolean supportsNullNotDistinct = false;

public PostgreSql() {
super(ID, "org.postgresql.Driver", "true", "false", "SELECT 1");
@@ -62,6 +64,12 @@ public class PostgreSql extends AbstractDialect {
return supportsUpsert;
}

@Override
public boolean supportsNullNotDistinct() {
checkState(initialized, "onInit() must be called before calling supportsNullNotDistinct()");
return supportsNullNotDistinct;
}

@Override
public void init(DatabaseMetaData metaData) throws SQLException {
checkState(!initialized, "onInit() must be called once");
@@ -69,6 +77,7 @@ public class PostgreSql extends AbstractDialect {
Version version = checkDbVersion(metaData, MIN_SUPPORTED_VERSION);

supportsUpsert = version.compareTo(MIN_UPSERT_VERSION) >= 0;
supportsNullNotDistinct = version.compareTo(MIN_NULL_NOT_DISTINCT_VERSION) >= 0;
if (!supportsUpsert) {
LoggerFactory.getLogger(getClass()).warn("Upgrading PostgreSQL to {} or greater is recommended for better performances", MIN_UPSERT_VERSION);
}

+ 5
- 0
server/sonar-db-core/src/test/java/org/sonar/db/dialect/H2Test.java 查看文件

@@ -80,4 +80,9 @@ public class H2Test {
public void supportsUpsert_returns_false() {
assertThat(underTest.supportsUpsert()).isFalse();
}

@Test
public void supportsNullNotDistinct_returns_true() {
assertThat(underTest.supportsNullNotDistinct()).isTrue();
}
}

+ 24
- 3
server/sonar-db-core/src/test/java/org/sonar/db/dialect/PostgreSqlTest.java 查看文件

@@ -82,7 +82,7 @@ public class PostgreSqlTest {
@Test
public void postgresql_9_2_is_not_supported() throws Exception {
assertThatThrownBy(() -> {
DatabaseMetaData metadata = newMetadata( 9, 2);
DatabaseMetaData metadata = newMetadata(9, 2);
underTest.init(metadata);
})
.isInstanceOf(MessageException.class)
@@ -91,7 +91,7 @@ public class PostgreSqlTest {

@Test
public void postgresql_9_3_is_supported_without_upsert() throws Exception {
DatabaseMetaData metadata = newMetadata( 9, 3);
DatabaseMetaData metadata = newMetadata(9, 3);
underTest.init(metadata);

assertThat(underTest.supportsUpsert()).isFalse();
@@ -100,7 +100,7 @@ public class PostgreSqlTest {

@Test
public void postgresql_9_5_is_supported_with_upsert() throws Exception {
DatabaseMetaData metadata = newMetadata( 9, 5);
DatabaseMetaData metadata = newMetadata(9, 5);
underTest.init(metadata);

assertThat(underTest.supportsUpsert()).isTrue();
@@ -124,6 +124,27 @@ public class PostgreSqlTest {
.hasMessage("onInit() must be called before calling supportsUpsert()");
}

@Test
public void supportsNullNotDistinct_throws_ISE_if_not_initialized() {
assertThatThrownBy(() -> underTest.supportsNullNotDistinct())
.isInstanceOf(IllegalStateException.class)
.hasMessage("onInit() must be called before calling supportsNullNotDistinct()");
}

@Test
public void supportsNullNotDistinct_shouldReturnTrue_WhenPostgres15OrGreater() throws SQLException {
DatabaseMetaData metadata = newMetadata(15, 0);
underTest.init(metadata);
assertThat(underTest.supportsNullNotDistinct()).isTrue();
}

@Test
public void supportsNullNotDistinct_shouldReturnFalse_WhenPostgres14OrLesser() throws SQLException {
DatabaseMetaData metadata = newMetadata(14, 0);
underTest.init(metadata);
assertThat(underTest.supportsNullNotDistinct()).isFalse();
}

private DatabaseMetaData newMetadata(int dbMajorVersion, int dbMinorVersion) throws SQLException {
DatabaseMetaData metadata = mock(DatabaseMetaData.class, Mockito.RETURNS_DEEP_STUBS);
when(metadata.getDatabaseMajorVersion()).thenReturn(dbMajorVersion);

+ 50
- 50
server/sonar-db-dao/src/schema/schema-sq.ddl 查看文件

@@ -33,7 +33,7 @@ CREATE TABLE "ACTIVE_RULES"(
"RULE_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "ACTIVE_RULES" ADD CONSTRAINT "PK_ACTIVE_RULES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROFILE_RULE_UUIDS" ON "ACTIVE_RULES"("PROFILE_UUID" NULLS FIRST, "RULE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROFILE_RULE_UUIDS" ON "ACTIVE_RULES"("PROFILE_UUID" NULLS FIRST, "RULE_UUID" NULLS FIRST);

CREATE TABLE "ALM_PATS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -44,7 +44,7 @@ CREATE TABLE "ALM_PATS"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "ALM_PATS" ADD CONSTRAINT "PK_ALM_PATS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_ALM_PATS" ON "ALM_PATS"("USER_UUID" NULLS FIRST, "ALM_SETTING_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_ALM_PATS" ON "ALM_PATS"("USER_UUID" NULLS FIRST, "ALM_SETTING_UUID" NULLS FIRST);

CREATE TABLE "ALM_SETTINGS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -61,7 +61,7 @@ CREATE TABLE "ALM_SETTINGS"(
"WEBHOOK_SECRET" CHARACTER VARYING(160)
);
ALTER TABLE "ALM_SETTINGS" ADD CONSTRAINT "PK_ALM_SETTINGS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_ALM_SETTINGS" ON "ALM_SETTINGS"("KEE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_ALM_SETTINGS" ON "ALM_SETTINGS"("KEE" NULLS FIRST);

CREATE TABLE "ANALYSIS_PROPERTIES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -99,7 +99,7 @@ CREATE TABLE "APP_BRANCH_PROJECT_BRANCH"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "APP_BRANCH_PROJECT_BRANCH" ADD CONSTRAINT "PK_APP_BRANCH_PROJECT_BRANCH" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_APP_BRANCH_PROJ" ON "APP_BRANCH_PROJECT_BRANCH"("APPLICATION_BRANCH_UUID" NULLS FIRST, "PROJECT_BRANCH_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_APP_BRANCH_PROJ" ON "APP_BRANCH_PROJECT_BRANCH"("APPLICATION_BRANCH_UUID" NULLS FIRST, "PROJECT_BRANCH_UUID" NULLS FIRST);
CREATE INDEX "IDX_ABPB_APP_UUID" ON "APP_BRANCH_PROJECT_BRANCH"("APPLICATION_UUID" NULLS FIRST);
CREATE INDEX "IDX_ABPB_APP_BRANCH_UUID" ON "APP_BRANCH_PROJECT_BRANCH"("APPLICATION_BRANCH_UUID" NULLS FIRST);
CREATE INDEX "IDX_ABPB_PROJ_UUID" ON "APP_BRANCH_PROJECT_BRANCH"("PROJECT_UUID" NULLS FIRST);
@@ -112,7 +112,7 @@ CREATE TABLE "APP_PROJECTS"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "APP_PROJECTS" ADD CONSTRAINT "PK_APP_PROJECTS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_APP_PROJECTS" ON "APP_PROJECTS"("APPLICATION_UUID" NULLS FIRST, "PROJECT_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_APP_PROJECTS" ON "APP_PROJECTS"("APPLICATION_UUID" NULLS FIRST, "PROJECT_UUID" NULLS FIRST);
CREATE INDEX "IDX_APP_PROJ_APPLICATION_UUID" ON "APP_PROJECTS"("APPLICATION_UUID" NULLS FIRST);
CREATE INDEX "IDX_APP_PROJ_PROJECT_UUID" ON "APP_PROJECTS"("PROJECT_UUID" NULLS FIRST);

@@ -244,9 +244,9 @@ CREATE TABLE "COMPONENTS"(
"CREATED_AT" TIMESTAMP
);
CREATE INDEX "PROJECTS_QUALIFIER" ON "COMPONENTS"("QUALIFIER" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "COMPONENTS_UUID" ON "COMPONENTS"("UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "COMPONENTS_UUID" ON "COMPONENTS"("UUID" NULLS FIRST);
CREATE INDEX "COMPONENTS_BRANCH_UUID" ON "COMPONENTS"("BRANCH_UUID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "COMPONENTS_KEE_BRANCH_UUID" ON "COMPONENTS"("KEE" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "COMPONENTS_KEE_BRANCH_UUID" ON "COMPONENTS"("KEE" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);

CREATE TABLE "DEFAULT_QPROFILES"(
"LANGUAGE" CHARACTER VARYING(20) NOT NULL,
@@ -255,7 +255,7 @@ CREATE TABLE "DEFAULT_QPROFILES"(
"UPDATED_AT" BIGINT NOT NULL
);
ALTER TABLE "DEFAULT_QPROFILES" ADD CONSTRAINT "PK_DEFAULT_QPROFILES" PRIMARY KEY("LANGUAGE");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_DEFAULT_QPROFILES_UUID" ON "DEFAULT_QPROFILES"("QPROFILE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_DEFAULT_QPROFILES_UUID" ON "DEFAULT_QPROFILES"("QPROFILE_UUID" NULLS FIRST);

CREATE TABLE "DEPRECATED_RULE_KEYS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -265,7 +265,7 @@ CREATE TABLE "DEPRECATED_RULE_KEYS"(
"RULE_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "DEPRECATED_RULE_KEYS" ADD CONSTRAINT "PK_DEPRECATED_RULE_KEYS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_DEPRECATED_RULE_KEYS" ON "DEPRECATED_RULE_KEYS"("OLD_REPOSITORY_KEY" NULLS FIRST, "OLD_RULE_KEY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_DEPRECATED_RULE_KEYS" ON "DEPRECATED_RULE_KEYS"("OLD_REPOSITORY_KEY" NULLS FIRST, "OLD_RULE_KEY" NULLS FIRST);
CREATE INDEX "RULE_UUID_DEPRECATED_RULE_KEYS" ON "DEPRECATED_RULE_KEYS"("RULE_UUID" NULLS FIRST);

CREATE TABLE "DUPLICATIONS_INDEX"(
@@ -305,7 +305,7 @@ CREATE TABLE "EVENT_COMPONENT_CHANGES"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "EVENT_COMPONENT_CHANGES" ADD CONSTRAINT "PK_EVENT_COMPONENT_CHANGES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "EVENT_COMPONENT_CHANGES_UNIQUE" ON "EVENT_COMPONENT_CHANGES"("EVENT_UUID" NULLS FIRST, "CHANGE_CATEGORY" NULLS FIRST, "COMPONENT_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "EVENT_COMPONENT_CHANGES_UNIQUE" ON "EVENT_COMPONENT_CHANGES"("EVENT_UUID" NULLS FIRST, "CHANGE_CATEGORY" NULLS FIRST, "COMPONENT_UUID" NULLS FIRST);
CREATE INDEX "EVENT_CPNT_CHANGES_CPNT" ON "EVENT_COMPONENT_CHANGES"("EVENT_COMPONENT_UUID" NULLS FIRST);
CREATE INDEX "EVENT_CPNT_CHANGES_ANALYSIS" ON "EVENT_COMPONENT_CHANGES"("EVENT_ANALYSIS_UUID" NULLS FIRST);

@@ -330,7 +330,7 @@ CREATE TABLE "EXTERNAL_GROUPS"(
"EXTERNAL_IDENTITY_PROVIDER" CHARACTER VARYING(100) NOT NULL
);
ALTER TABLE "EXTERNAL_GROUPS" ADD CONSTRAINT "PK_EXTERNAL_GROUPS" PRIMARY KEY("GROUP_UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_EXT_GRP_EXT_ID_PROVIDER" ON "EXTERNAL_GROUPS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_GROUP_ID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_EXT_GRP_EXT_ID_PROVIDER" ON "EXTERNAL_GROUPS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_GROUP_ID" NULLS FIRST);

CREATE TABLE "FILE_SOURCES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -347,7 +347,7 @@ CREATE TABLE "FILE_SOURCES"(
"UPDATED_AT" BIGINT NOT NULL
);
ALTER TABLE "FILE_SOURCES" ADD CONSTRAINT "PK_FILE_SOURCES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "FILE_SOURCES_FILE_UUID" ON "FILE_SOURCES"("FILE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "FILE_SOURCES_FILE_UUID" ON "FILE_SOURCES"("FILE_UUID" NULLS FIRST);
CREATE INDEX "FILE_SOURCES_PROJECT_UUID" ON "FILE_SOURCES"("PROJECT_UUID" NULLS FIRST);
CREATE INDEX "FILE_SOURCES_UPDATED_AT" ON "FILE_SOURCES"("UPDATED_AT" NULLS FIRST);

@@ -363,7 +363,7 @@ CREATE TABLE "GITHUB_PERMS_MAPPING"(
"SONARQUBE_PERMISSION" CHARACTER VARYING(64) NOT NULL
);
ALTER TABLE "GITHUB_PERMS_MAPPING" ADD CONSTRAINT "PK_GITHUB_PERMS_MAPPING" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_GITHUB_PERM_MAPPINGS" ON "GITHUB_PERMS_MAPPING"("GITHUB_ROLE" NULLS FIRST, "SONARQUBE_PERMISSION" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_GITHUB_PERM_MAPPINGS" ON "GITHUB_PERMS_MAPPING"("GITHUB_ROLE" NULLS FIRST, "SONARQUBE_PERMISSION" NULLS FIRST);

CREATE TABLE "GROUP_ROLES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -372,7 +372,7 @@ CREATE TABLE "GROUP_ROLES"(
"GROUP_UUID" CHARACTER VARYING(40)
);
ALTER TABLE "GROUP_ROLES" ADD CONSTRAINT "PK_GROUP_ROLES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_GROUP_ROLES" ON "GROUP_ROLES"("GROUP_UUID" NULLS FIRST, "ENTITY_UUID" NULLS FIRST, "ROLE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_GROUP_ROLES" ON "GROUP_ROLES"("GROUP_UUID" NULLS FIRST, "ENTITY_UUID" NULLS FIRST, "ROLE" NULLS FIRST);
CREATE INDEX "GROUP_ROLES_ENTITY_UUID" ON "GROUP_ROLES"("ENTITY_UUID" NULLS FIRST);

CREATE TABLE "GROUPS"(
@@ -383,7 +383,7 @@ CREATE TABLE "GROUPS"(
"UPDATED_AT" TIMESTAMP
);
ALTER TABLE "GROUPS" ADD CONSTRAINT "PK_GROUPS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_GROUPS_NAME" ON "GROUPS"("NAME" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_GROUPS_NAME" ON "GROUPS"("NAME" NULLS FIRST);

CREATE TABLE "GROUPS_USERS"(
"GROUP_UUID" CHARACTER VARYING(40) NOT NULL,
@@ -391,7 +391,7 @@ CREATE TABLE "GROUPS_USERS"(
);
CREATE INDEX "INDEX_GROUPS_USERS_GROUP_UUID" ON "GROUPS_USERS"("GROUP_UUID" NULLS FIRST);
CREATE INDEX "INDEX_GROUPS_USERS_USER_UUID" ON "GROUPS_USERS"("USER_UUID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "GROUPS_USERS_UNIQUE" ON "GROUPS_USERS"("USER_UUID" NULLS FIRST, "GROUP_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "GROUPS_USERS_UNIQUE" ON "GROUPS_USERS"("USER_UUID" NULLS FIRST, "GROUP_UUID" NULLS FIRST);

CREATE TABLE "INTERNAL_COMPONENT_PROPS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -402,7 +402,7 @@ CREATE TABLE "INTERNAL_COMPONENT_PROPS"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "INTERNAL_COMPONENT_PROPS" ADD CONSTRAINT "PK_INTERNAL_COMPONENT_PROPS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQUE_COMPONENT_UUID_KEE" ON "INTERNAL_COMPONENT_PROPS"("COMPONENT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQUE_COMPONENT_UUID_KEE" ON "INTERNAL_COMPONENT_PROPS"("COMPONENT_UUID" NULLS FIRST, "KEE" NULLS FIRST);

CREATE TABLE "INTERNAL_PROPERTIES"(
"KEE" CHARACTER VARYING(40) NOT NULL,
@@ -478,7 +478,7 @@ CREATE TABLE "ISSUES_IMPACTS"(
"SEVERITY" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "ISSUES_IMPACTS" ADD CONSTRAINT "PK_ISSUES_IMPACTS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_ISS_KEY_SOF_QUAL" ON "ISSUES_IMPACTS"("ISSUE_KEY" NULLS FIRST, "SOFTWARE_QUALITY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_ISS_KEY_SOF_QUAL" ON "ISSUES_IMPACTS"("ISSUE_KEY" NULLS FIRST, "SOFTWARE_QUALITY" NULLS FIRST);

CREATE TABLE "LIVE_MEASURES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -494,7 +494,7 @@ CREATE TABLE "LIVE_MEASURES"(
);
ALTER TABLE "LIVE_MEASURES" ADD CONSTRAINT "PK_LIVE_MEASURES" PRIMARY KEY("UUID");
CREATE INDEX "LIVE_MEASURES_PROJECT" ON "LIVE_MEASURES"("PROJECT_UUID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "LIVE_MEASURES_COMPONENT" ON "LIVE_MEASURES"("COMPONENT_UUID" NULLS FIRST, "METRIC_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "LIVE_MEASURES_COMPONENT" ON "LIVE_MEASURES"("COMPONENT_UUID" NULLS FIRST, "METRIC_UUID" NULLS FIRST);

CREATE TABLE "METRICS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -514,7 +514,7 @@ CREATE TABLE "METRICS"(
"DECIMAL_SCALE" INTEGER
);
ALTER TABLE "METRICS" ADD CONSTRAINT "PK_METRICS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "METRICS_UNIQUE_NAME" ON "METRICS"("NAME" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "METRICS_UNIQUE_NAME" ON "METRICS"("NAME" NULLS FIRST);

CREATE TABLE "NEW_CODE_PERIODS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -527,7 +527,7 @@ CREATE TABLE "NEW_CODE_PERIODS"(
"PREVIOUS_NON_COMPLIANT_VALUE" CHARACTER VARYING(255)
);
ALTER TABLE "NEW_CODE_PERIODS" ADD CONSTRAINT "PK_NEW_CODE_PERIODS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_NEW_CODE_PERIODS" ON "NEW_CODE_PERIODS"("PROJECT_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_NEW_CODE_PERIODS" ON "NEW_CODE_PERIODS"("PROJECT_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);
CREATE INDEX "IDX_NCP_TYPE" ON "NEW_CODE_PERIODS"("TYPE" NULLS FIRST);
CREATE INDEX "IDX_NCP_VALUE" ON "NEW_CODE_PERIODS"("VALUE" NULLS FIRST);

@@ -537,7 +537,7 @@ CREATE TABLE "NEW_CODE_REFERENCE_ISSUES"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "NEW_CODE_REFERENCE_ISSUES" ADD CONSTRAINT "PK_NEW_CODE_REFERENCE_ISSUES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_NEW_CODE_REFERENCE_ISSUES" ON "NEW_CODE_REFERENCE_ISSUES"("ISSUE_KEY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_NEW_CODE_REFERENCE_ISSUES" ON "NEW_CODE_REFERENCE_ISSUES"("ISSUE_KEY" NULLS FIRST);

CREATE TABLE "NOTIFICATIONS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -588,7 +588,7 @@ CREATE TABLE "PERM_TPL_CHARACTERISTICS"(
"TEMPLATE_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "PERM_TPL_CHARACTERISTICS" ADD CONSTRAINT "PK_PERM_TPL_CHARACTERISTICS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PERM_TPL_CHARAC" ON "PERM_TPL_CHARACTERISTICS"("TEMPLATE_UUID" NULLS FIRST, "PERMISSION_KEY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PERM_TPL_CHARAC" ON "PERM_TPL_CHARACTERISTICS"("TEMPLATE_UUID" NULLS FIRST, "PERMISSION_KEY" NULLS FIRST);

CREATE TABLE "PERMISSION_TEMPLATES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -611,7 +611,7 @@ CREATE TABLE "PLUGINS"(
"REMOVED" BOOLEAN DEFAULT FALSE NOT NULL
);
ALTER TABLE "PLUGINS" ADD CONSTRAINT "PK_PLUGINS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "PLUGINS_KEY" ON "PLUGINS"("KEE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "PLUGINS_KEY" ON "PLUGINS"("KEE" NULLS FIRST);

CREATE TABLE "PORTFOLIO_PROJ_BRANCHES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -628,7 +628,7 @@ CREATE TABLE "PORTFOLIO_PROJECTS"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "PORTFOLIO_PROJECTS" ADD CONSTRAINT "PK_PORTFOLIO_PROJECTS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PORTFOLIO_PROJECTS" ON "PORTFOLIO_PROJECTS"("PORTFOLIO_UUID" NULLS FIRST, "PROJECT_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PORTFOLIO_PROJECTS" ON "PORTFOLIO_PROJECTS"("PORTFOLIO_UUID" NULLS FIRST, "PROJECT_UUID" NULLS FIRST);

CREATE TABLE "PORTFOLIO_REFERENCES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -638,7 +638,7 @@ CREATE TABLE "PORTFOLIO_REFERENCES"(
"BRANCH_UUID" CHARACTER VARYING(255)
);
ALTER TABLE "PORTFOLIO_REFERENCES" ADD CONSTRAINT "PK_PORTFOLIO_REFERENCES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PORTFOLIO_REFERENCES" ON "PORTFOLIO_REFERENCES"("PORTFOLIO_UUID" NULLS FIRST, "REFERENCE_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PORTFOLIO_REFERENCES" ON "PORTFOLIO_REFERENCES"("PORTFOLIO_UUID" NULLS FIRST, "REFERENCE_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);

CREATE TABLE "PORTFOLIOS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -655,7 +655,7 @@ CREATE TABLE "PORTFOLIOS"(
"BRANCH_KEY" CHARACTER VARYING(255)
);
ALTER TABLE "PORTFOLIOS" ADD CONSTRAINT "PK_PORTFOLIOS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PORTFOLIOS_KEE" ON "PORTFOLIOS"("KEE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PORTFOLIOS_KEE" ON "PORTFOLIOS"("KEE" NULLS FIRST);

CREATE TABLE "PROJECT_ALM_SETTINGS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -669,7 +669,7 @@ CREATE TABLE "PROJECT_ALM_SETTINGS"(
"MONOREPO" BOOLEAN NOT NULL
);
ALTER TABLE "PROJECT_ALM_SETTINGS" ADD CONSTRAINT "PK_PROJECT_ALM_SETTINGS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROJECT_ALM_SETTINGS" ON "PROJECT_ALM_SETTINGS"("PROJECT_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROJECT_ALM_SETTINGS" ON "PROJECT_ALM_SETTINGS"("PROJECT_UUID" NULLS FIRST);
CREATE INDEX "PROJECT_ALM_SETTINGS_ALM" ON "PROJECT_ALM_SETTINGS"("ALM_SETTING_UUID" NULLS FIRST);
CREATE INDEX "PROJECT_ALM_SETTINGS_SLUG" ON "PROJECT_ALM_SETTINGS"("ALM_SLUG" NULLS FIRST);

@@ -681,7 +681,7 @@ CREATE TABLE "PROJECT_BADGE_TOKEN"(
"UPDATED_AT" BIGINT NOT NULL
);
ALTER TABLE "PROJECT_BADGE_TOKEN" ADD CONSTRAINT "PK_PROJECT_BADGE_TOKEN" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROJECT_BADGE_TOKEN" ON "PROJECT_BADGE_TOKEN"("PROJECT_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROJECT_BADGE_TOKEN" ON "PROJECT_BADGE_TOKEN"("PROJECT_UUID" NULLS FIRST);

CREATE TABLE "PROJECT_BRANCHES"(
"UUID" CHARACTER VARYING(50) NOT NULL,
@@ -698,7 +698,7 @@ CREATE TABLE "PROJECT_BRANCHES"(
"IS_MAIN" BOOLEAN NOT NULL
);
ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
CREATE INDEX "PROJECT_BRANCHES_PROJECT_UUID" ON "PROJECT_BRANCHES"("PROJECT_UUID" NULLS FIRST);

CREATE TABLE "PROJECT_LINKS"(
@@ -735,7 +735,7 @@ CREATE TABLE "PROJECT_QGATES"(
"QUALITY_GATE_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "PROJECT_QGATES" ADD CONSTRAINT "PK_PROJECT_QGATES" PRIMARY KEY("PROJECT_UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROJECT_QGATES" ON "PROJECT_QGATES"("PROJECT_UUID" NULLS FIRST, "QUALITY_GATE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROJECT_QGATES" ON "PROJECT_QGATES"("PROJECT_UUID" NULLS FIRST, "QUALITY_GATE_UUID" NULLS FIRST);

CREATE TABLE "PROJECT_QPROFILES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -743,7 +743,7 @@ CREATE TABLE "PROJECT_QPROFILES"(
"PROFILE_KEY" CHARACTER VARYING(50) NOT NULL
);
ALTER TABLE "PROJECT_QPROFILES" ADD CONSTRAINT "PK_PROJECT_QPROFILES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROJECT_QPROFILES" ON "PROJECT_QPROFILES"("PROJECT_UUID" NULLS FIRST, "PROFILE_KEY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROJECT_QPROFILES" ON "PROJECT_QPROFILES"("PROJECT_UUID" NULLS FIRST, "PROFILE_KEY" NULLS FIRST);

CREATE TABLE "PROJECTS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -759,7 +759,7 @@ CREATE TABLE "PROJECTS"(
"CREATION_METHOD" CHARACTER VARYING(50) NOT NULL
);
ALTER TABLE "PROJECTS" ADD CONSTRAINT "PK_NEW_PROJECTS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_PROJECTS_KEE" ON "PROJECTS"("KEE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_PROJECTS_KEE" ON "PROJECTS"("KEE" NULLS FIRST);
CREATE INDEX "IDX_QUALIFIER" ON "PROJECTS"("QUALIFIER" NULLS FIRST);

CREATE TABLE "PROPERTIES"(
@@ -825,7 +825,7 @@ CREATE TABLE "QPROFILE_EDIT_GROUPS"(
);
ALTER TABLE "QPROFILE_EDIT_GROUPS" ADD CONSTRAINT "PK_QPROFILE_EDIT_GROUPS" PRIMARY KEY("UUID");
CREATE INDEX "QPROFILE_EDIT_GROUPS_QPROFILE" ON "QPROFILE_EDIT_GROUPS"("QPROFILE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "QPROFILE_EDIT_GROUPS_UNIQUE" ON "QPROFILE_EDIT_GROUPS"("GROUP_UUID" NULLS FIRST, "QPROFILE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "QPROFILE_EDIT_GROUPS_UNIQUE" ON "QPROFILE_EDIT_GROUPS"("GROUP_UUID" NULLS FIRST, "QPROFILE_UUID" NULLS FIRST);

CREATE TABLE "QPROFILE_EDIT_USERS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -835,7 +835,7 @@ CREATE TABLE "QPROFILE_EDIT_USERS"(
);
ALTER TABLE "QPROFILE_EDIT_USERS" ADD CONSTRAINT "PK_QPROFILE_EDIT_USERS" PRIMARY KEY("UUID");
CREATE INDEX "QPROFILE_EDIT_USERS_QPROFILE" ON "QPROFILE_EDIT_USERS"("QPROFILE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "QPROFILE_EDIT_USERS_UNIQUE" ON "QPROFILE_EDIT_USERS"("USER_UUID" NULLS FIRST, "QPROFILE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "QPROFILE_EDIT_USERS_UNIQUE" ON "QPROFILE_EDIT_USERS"("USER_UUID" NULLS FIRST, "QPROFILE_UUID" NULLS FIRST);

CREATE TABLE "QUALITY_GATE_CONDITIONS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -864,7 +864,7 @@ CREATE TABLE "REPORT_SCHEDULES"(
"LAST_SEND_TIME_IN_MS" BIGINT NOT NULL
);
ALTER TABLE "REPORT_SCHEDULES" ADD CONSTRAINT "PK_REPORT_SCHEDULES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_REPORT_SCHEDULES" ON "REPORT_SCHEDULES"("PORTFOLIO_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_REPORT_SCHEDULES" ON "REPORT_SCHEDULES"("PORTFOLIO_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST);

CREATE TABLE "REPORT_SUBSCRIPTIONS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -873,7 +873,7 @@ CREATE TABLE "REPORT_SUBSCRIPTIONS"(
"USER_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "REPORT_SUBSCRIPTIONS" ADD CONSTRAINT "PK_REPORT_SUBSCRIPTIONS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_REPORT_SUBSCRIPTIONS" ON "REPORT_SUBSCRIPTIONS"("PORTFOLIO_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST, "USER_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_REPORT_SUBSCRIPTIONS" ON "REPORT_SUBSCRIPTIONS"("PORTFOLIO_UUID" NULLS FIRST, "BRANCH_UUID" NULLS FIRST, "USER_UUID" NULLS FIRST);

CREATE TABLE "RULE_CHANGES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -892,7 +892,7 @@ CREATE TABLE "RULE_DESC_SECTIONS"(
"CONTEXT_DISPLAY_NAME" CHARACTER VARYING(50)
);
ALTER TABLE "RULE_DESC_SECTIONS" ADD CONSTRAINT "PK_RULE_DESC_SECTIONS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_RULE_DESC_SECTIONS" ON "RULE_DESC_SECTIONS"("RULE_UUID" NULLS FIRST, "KEE" NULLS FIRST, "CONTEXT_KEY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_RULE_DESC_SECTIONS" ON "RULE_DESC_SECTIONS"("RULE_UUID" NULLS FIRST, "KEE" NULLS FIRST, "CONTEXT_KEY" NULLS FIRST);

CREATE TABLE "RULE_IMPACT_CHANGES"(
"NEW_SOFTWARE_QUALITY" CHARACTER VARYING(40),
@@ -952,7 +952,7 @@ CREATE TABLE "RULES"(
"CLEAN_CODE_ATTRIBUTE" CHARACTER VARYING(40)
);
ALTER TABLE "RULES" ADD CONSTRAINT "PK_RULES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "RULES_REPO_KEY" ON "RULES"("PLUGIN_RULE_KEY" NULLS FIRST, "PLUGIN_NAME" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "RULES_REPO_KEY" ON "RULES"("PLUGIN_RULE_KEY" NULLS FIRST, "PLUGIN_NAME" NULLS FIRST);

CREATE TABLE "RULES_DEFAULT_IMPACTS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -961,7 +961,7 @@ CREATE TABLE "RULES_DEFAULT_IMPACTS"(
"SEVERITY" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "RULES_DEFAULT_IMPACTS" ADD CONSTRAINT "PK_RULES_DEFAULT_IMPACTS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_RUL_UUID_SOF_QUAL" ON "RULES_DEFAULT_IMPACTS"("RULE_UUID" NULLS FIRST, "SOFTWARE_QUALITY" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_RUL_UUID_SOF_QUAL" ON "RULES_DEFAULT_IMPACTS"("RULE_UUID" NULLS FIRST, "SOFTWARE_QUALITY" NULLS FIRST);

CREATE TABLE "RULES_PARAMETERS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -973,7 +973,7 @@ CREATE TABLE "RULES_PARAMETERS"(
);
ALTER TABLE "RULES_PARAMETERS" ADD CONSTRAINT "PK_RULES_PARAMETERS" PRIMARY KEY("UUID");
CREATE INDEX "RULES_PARAMETERS_RULE_UUID" ON "RULES_PARAMETERS"("RULE_UUID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "RULES_PARAMETERS_UNIQUE" ON "RULES_PARAMETERS"("RULE_UUID" NULLS FIRST, "NAME" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "RULES_PARAMETERS_UNIQUE" ON "RULES_PARAMETERS"("RULE_UUID" NULLS FIRST, "NAME" NULLS FIRST);

CREATE TABLE "RULES_PROFILES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -993,7 +993,7 @@ CREATE TABLE "SAML_MESSAGE_IDS"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "SAML_MESSAGE_IDS" ADD CONSTRAINT "PK_SAML_MESSAGE_IDS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "SAML_MESSAGE_IDS_UNIQUE" ON "SAML_MESSAGE_IDS"("MESSAGE_ID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "SAML_MESSAGE_IDS_UNIQUE" ON "SAML_MESSAGE_IDS"("MESSAGE_ID" NULLS FIRST);

CREATE TABLE "SCANNER_ANALYSIS_CACHE"(
"BRANCH_UUID" CHARACTER VARYING(40) NOT NULL,
@@ -1006,14 +1006,14 @@ CREATE TABLE "SCIM_GROUPS"(
"GROUP_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "SCIM_GROUPS" ADD CONSTRAINT "PK_SCIM_GROUPS" PRIMARY KEY("SCIM_UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_SCIM_GROUP_UUID" ON "SCIM_GROUPS"("GROUP_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_SCIM_GROUP_UUID" ON "SCIM_GROUPS"("GROUP_UUID" NULLS FIRST);

CREATE TABLE "SCIM_USERS"(
"SCIM_UUID" CHARACTER VARYING(40) NOT NULL,
"USER_UUID" CHARACTER VARYING(40) NOT NULL
);
ALTER TABLE "SCIM_USERS" ADD CONSTRAINT "PK_SCIM_USERS" PRIMARY KEY("SCIM_UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_SCIM_USERS_USER_UUID" ON "SCIM_USERS"("USER_UUID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_SCIM_USERS_USER_UUID" ON "SCIM_USERS"("USER_UUID" NULLS FIRST);

CREATE TABLE "SCM_ACCOUNTS"(
"USER_UUID" CHARACTER VARYING(255) NOT NULL,
@@ -1058,7 +1058,7 @@ CREATE TABLE "USER_DISMISSED_MESSAGES"(
"CREATED_AT" BIGINT NOT NULL
);
ALTER TABLE "USER_DISMISSED_MESSAGES" ADD CONSTRAINT "PK_USER_DISMISSED_MESSAGES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_USER_DISMISSED_MESSAGES" ON "USER_DISMISSED_MESSAGES"("USER_UUID" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "MESSAGE_TYPE" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_USER_DISMISSED_MESSAGES" ON "USER_DISMISSED_MESSAGES"("USER_UUID" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "MESSAGE_TYPE" NULLS FIRST);
CREATE INDEX "UDM_PROJECT_UUID" ON "USER_DISMISSED_MESSAGES"("PROJECT_UUID" NULLS FIRST);
CREATE INDEX "UDM_MESSAGE_TYPE" ON "USER_DISMISSED_MESSAGES"("MESSAGE_TYPE" NULLS FIRST);

@@ -1084,8 +1084,8 @@ CREATE TABLE "USER_TOKENS"(
"PROJECT_UUID" CHARACTER VARYING(40)
);
ALTER TABLE "USER_TOKENS" ADD CONSTRAINT "PK_USER_TOKENS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "USER_TOKENS_USER_UUID_NAME" ON "USER_TOKENS"("USER_UUID" NULLS FIRST, "NAME" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "USER_TOKENS_TOKEN_HASH" ON "USER_TOKENS"("TOKEN_HASH" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "USER_TOKENS_USER_UUID_NAME" ON "USER_TOKENS"("USER_UUID" NULLS FIRST, "NAME" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "USER_TOKENS_TOKEN_HASH" ON "USER_TOKENS"("TOKEN_HASH" NULLS FIRST);

CREATE TABLE "USERS"(
"UUID" CHARACTER VARYING(255) NOT NULL,
@@ -1109,10 +1109,10 @@ CREATE TABLE "USERS"(
"LAST_SONARLINT_CONNECTION" BIGINT
);
ALTER TABLE "USERS" ADD CONSTRAINT "PK_USERS" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS DISTINCT INDEX "USERS_LOGIN" ON "USERS"("LOGIN" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "USERS_LOGIN" ON "USERS"("LOGIN" NULLS FIRST);
CREATE INDEX "USERS_UPDATED_AT" ON "USERS"("UPDATED_AT" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_EXTERNAL_ID" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_ID" NULLS FIRST);
CREATE UNIQUE NULLS DISTINCT INDEX "UNIQ_EXTERNAL_LOGIN" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_LOGIN" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_EXTERNAL_ID" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_ID" NULLS FIRST);
CREATE UNIQUE NULLS NOT DISTINCT INDEX "UNIQ_EXTERNAL_LOGIN" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_LOGIN" NULLS FIRST);
CREATE INDEX "USERS_EMAIL" ON "USERS"("EMAIL" NULLS FIRST);

CREATE TABLE "WEBHOOK_DELIVERIES"(

+ 52
- 4
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/CreateIndexBuilder.java 查看文件

@@ -21,6 +21,9 @@ package org.sonar.server.platform.db.migration.sql;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.sonar.db.dialect.Dialect;
import org.sonar.db.dialect.PostgreSql;
import org.sonar.server.platform.db.migration.def.ColumnDef;

import static com.google.common.base.Preconditions.checkArgument;
@@ -31,11 +34,17 @@ import static org.sonar.server.platform.db.migration.def.Validations.validateTab

public class CreateIndexBuilder {

private final List<String> columns = new ArrayList<>();
private static final String COLUMN_CANNOT_BE_NULL = "Column cannot be null";
private final List<NullableColumn> columns = new ArrayList<>();
private final Dialect dialect;
private String tableName;
private String indexName;
private boolean unique = false;

public CreateIndexBuilder(Dialect dialect) {
this.dialect = dialect;
}

/**
* Required name of table on which index is created
*/
@@ -68,16 +77,27 @@ public class CreateIndexBuilder {
* Other attributes are ignored.
*/
public CreateIndexBuilder addColumn(ColumnDef column) {
columns.add(requireNonNull(column, "Column cannot be null").getName());
requireNonNull(column, COLUMN_CANNOT_BE_NULL);
columns.add(new NullableColumn(column.getName(), column.isNullable()));
return this;
}

/**
* Add a column to the scope of index. Order of calls to this
* method is important and is kept as-is when creating the index.
*
* @deprecated use {@link CreateIndexBuilder#addColumn(String, boolean) instead}
*/
@Deprecated(since = "10.3")
public CreateIndexBuilder addColumn(String column) {
columns.add(requireNonNull(column, "Column cannot be null"));
requireNonNull(column, COLUMN_CANNOT_BE_NULL);
columns.add(new NullableColumn(column, false));
return this;
}

public CreateIndexBuilder addColumn(String column, boolean isNullable) {
requireNonNull(column, COLUMN_CANNOT_BE_NULL);
columns.add(new NullableColumn(column, isNullable));
return this;
}

@@ -88,18 +108,46 @@ public class CreateIndexBuilder {
return singletonList(createSqlStatement());
}

/**
*
*/
private String createSqlStatement() {
StringBuilder sql = new StringBuilder("CREATE ");
if (unique) {
sql.append("UNIQUE ");
if (dialect.supportsNullNotDistinct() && !PostgreSql.ID.equals(dialect.getId())) {
sql.append("NULLS NOT DISTINCT ");
}
}
sql.append("INDEX ");
sql.append(indexName);
sql.append(" ON ");
sql.append(tableName);
sql.append(" (");
sql.append(String.join(", ", columns));

/*
* Oldest versions of postgres don't support NULLS NOT DISTINCT, and their default behavior is NULLS DISTINCT.
* To make sure we apply the same constraints as other DB vendors, we use coalesce to default to empty string, to ensure unicity constraint.
* Other db vendors are not impacted since they fall back to NULLS NOT DISTINCT by default.
*/
if (unique && !dialect.supportsNullNotDistinct() && PostgreSql.ID.equals(dialect.getId())) {
sql.append(columns.stream()
.map(c -> c.isNullable() ? "COALESCE(%s, '')".formatted(c.name()) : c.name())
.collect(Collectors.joining(", ")));
} else {
sql.append(columns.stream()
.map(NullableColumn::name)
.collect(Collectors.joining(", ")));
}

sql.append(")");

if (unique && dialect.supportsNullNotDistinct() && PostgreSql.ID.equals(dialect.getId())) {
sql.append(" NULLS NOT DISTINCT");
}
return sql.toString();
}

private record NullableColumn(String name, boolean isNullable) {
}
}

+ 1
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/CreateIndexOnColumn.java 查看文件

@@ -42,7 +42,7 @@ public abstract class CreateIndexOnColumn extends DdlChange {
public void execute(Context context) throws SQLException {
try (Connection connection = getDatabase().getDataSource().getConnection()) {
if (!DatabaseUtils.indexExistsIgnoreCase(table, newIndexName(), connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(table)
.setName(newIndexName())
.addColumn(columnName)

+ 1
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/CreateIndexOnColumns.java 查看文件

@@ -44,7 +44,7 @@ public abstract class CreateIndexOnColumns extends DdlChange {
public void execute(Context context) throws SQLException {
try (Connection connection = getDatabase().getDataSource().getConnection()) {
if (!DatabaseUtils.indexExistsIgnoreCase(table, newIndexName(), connection)) {
CreateIndexBuilder builder = new CreateIndexBuilder()
CreateIndexBuilder builder = new CreateIndexBuilder(getDialect())
.setTable(table)
.setName(newIndexName())
.setUnique(unique);

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v00/CreateInitialSchema.java 查看文件

@@ -1607,8 +1607,8 @@ public class CreateInitialSchema extends DdlChange {
.build());
}

private static void addIndex(Context context, String table, String index, boolean unique, ColumnDef firstColumn, ColumnDef... otherColumns) {
CreateIndexBuilder builder = new CreateIndexBuilder()
private void addIndex(Context context, String table, String index, boolean unique, ColumnDef firstColumn, ColumnDef... otherColumns) {
CreateIndexBuilder builder = new CreateIndexBuilder(getDialect())
.setTable(table)
.setName(index)
.setUnique(unique);

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v100/CreateUniqueIndexForScimGroupsUuid.java 查看文件

@@ -48,9 +48,9 @@ public class CreateUniqueIndexForScimGroupsUuid extends DdlChange {
}
}

private static void createUserUuidUniqueIndex(Context context, Connection connection) {
private void createUserUuidUniqueIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn(COLUMN_NAME)

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateIndexForEmailOnUsersTable.java 查看文件

@@ -47,9 +47,9 @@ class CreateIndexForEmailOnUsersTable extends DdlChange {
}
}

private static void createIndex(Context context, Connection connection) {
private void createIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn(COLUMN_NAME)

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateIndexForScmAccountOnScmAccountsTable.java 查看文件

@@ -46,9 +46,9 @@ class CreateIndexForScmAccountOnScmAccountsTable extends DdlChange {
}
}

private static void createIndex(Context context, Connection connection) {
private void createIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(SCM_ACCOUNTS_TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(SCM_ACCOUNTS_TABLE_NAME)
.setName(INDEX_NAME)
.addColumn(SCM_ACCOUNT_COLUMN_NAME)

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateIndexOnExternalIdAndIdentityOnExternalGroupsTable.java 查看文件

@@ -47,9 +47,9 @@ public class CreateIndexOnExternalIdAndIdentityOnExternalGroupsTable extends Ddl
}
}

private static void createIndex(Context context, Connection connection) {
private void createIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn(EXTERNAL_IDENTITY_PROVIDER_COLUMN_NAME)

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateUniqueIndexForReportSchedulesTable.java 查看文件

@@ -52,9 +52,9 @@ public class CreateUniqueIndexForReportSchedulesTable extends DdlChange {
}
}

private static void createUserUuidUniqueIndex(Context context, Connection connection) {
private void createUserUuidUniqueIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn(COLUMN_NAME_PORTFOLIO)

+ 3
- 3
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v101/CreateUniqueIndexForReportSubscriptionsTable.java 查看文件

@@ -30,7 +30,7 @@ import org.sonar.server.platform.db.migration.step.DdlChange;
import static org.sonar.server.platform.db.migration.version.v101.AddReportSubscriptionsTable.TABLE_NAME;


public class CreateUniqueIndexForReportSubscriptionsTable extends DdlChange{
public class CreateUniqueIndexForReportSubscriptionsTable extends DdlChange {

@VisibleForTesting
static final String COLUMN_NAME_PORTFOLIO = "portfolio_uuid";
@@ -55,9 +55,9 @@ public class CreateUniqueIndexForReportSubscriptionsTable extends DdlChange{
}
}

private static void createUserUuidUniqueIndex(DdlChange.Context context, Connection connection) {
private void createUserUuidUniqueIndex(DdlChange.Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn(COLUMN_NAME_PORTFOLIO)

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateUniqueConstraintOnIssuesImpacts.java 查看文件

@@ -41,9 +41,9 @@ public class CreateUniqueConstraintOnIssuesImpacts extends DdlChange {
}
}

private static void createIndex(Context context, Connection connection) {
private void createIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn("issue_key")

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateUniqueConstraintOnRulesDefaultImpacts.java 查看文件

@@ -41,9 +41,9 @@ public class CreateUniqueConstraintOnRulesDefaultImpacts extends DdlChange {
}
}

private static void createIndex(Context context, Connection connection) {
private void createIndex(Context context, Connection connection) {
if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
context.execute(new CreateIndexBuilder()
context.execute(new CreateIndexBuilder(getDialect())
.setTable(TABLE_NAME)
.setName(INDEX_NAME)
.addColumn("rule_uuid")

+ 84
- 29
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/sql/CreateIndexBuilderTest.java 查看文件

@@ -19,8 +19,14 @@
*/
package org.sonar.server.platform.db.migration.sql;

import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.List;
import org.junit.Test;
import org.mockito.Mockito;
import org.sonar.db.dialect.H2;
import org.sonar.db.dialect.Oracle;
import org.sonar.db.dialect.PostgreSql;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -29,57 +35,106 @@ import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVar
public class CreateIndexBuilderTest {
@Test
public void create_index_on_single_column() {
verifySql(new CreateIndexBuilder()
.setTable("issues")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build()),
verifySql(new CreateIndexBuilder(new Oracle())
.setTable("issues")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build()),
"CREATE INDEX issues_key ON issues (kee)");
}

@Test
public void create_unique_index_on_single_column() {
verifySql(new CreateIndexBuilder()
.setTable("issues")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build())
.setUnique(true),
verifySql(new CreateIndexBuilder(new Oracle())
.setTable("issues")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build())
.setUnique(true),
"CREATE UNIQUE INDEX issues_key ON issues (kee)");
}

@Test
public void create_index_on_multiple_columns() {
verifySql(new CreateIndexBuilder()
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).build()),
verifySql(new CreateIndexBuilder(new Oracle())
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).build()),
"CREATE INDEX rules_key ON rules (repository, rule_key)");
}

@Test
public void create_unique_index_on_multiple_columns() {
verifySql(new CreateIndexBuilder()
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).build())
.setUnique(true),
verifySql(new CreateIndexBuilder(new Oracle())
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).build())
.setUnique(true),
"CREATE UNIQUE INDEX rules_key ON rules (repository, rule_key)");
}

@Test
public void build_whenDialectH2_shouldHaveNullsNotDistinctClause() {
verifySql(new CreateIndexBuilder(new H2())
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).build())
.setUnique(true),
"CREATE UNIQUE NULLS NOT DISTINCT INDEX rules_key ON rules (repository, rule_key)");
}

@Test
public void build_whenDialectPostgres15_shouldHaveNullsNotDistinctClause() throws SQLException {
PostgreSql postgreSql = new PostgreSql();
getMetadataForDbVersion(15, 0);
postgreSql.init(getMetadataForDbVersion(15, 0));

verifySql(new CreateIndexBuilder(postgreSql)
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).build())
.setUnique(true),
"CREATE UNIQUE INDEX rules_key ON rules (repository, rule_key) NULLS NOT DISTINCT");
}

@Test
public void build_whenDialectPostgres14OrLower_shouldHaveCoalesceConditionsOnNullableColumns() throws SQLException {
PostgreSql postgreSql = new PostgreSql();
getMetadataForDbVersion(14, 0);
postgreSql.init(getMetadataForDbVersion(14, 0));

verifySql(new CreateIndexBuilder(postgreSql)
.setTable("rules")
.setName("rules_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("repository").setLimit(10).build())
.addColumn(newVarcharColumnDefBuilder().setColumnName("rule_key").setLimit(50).setIsNullable(false).build())
.setUnique(true),
"CREATE UNIQUE INDEX rules_key ON rules (COALESCE(repository, ''), rule_key)");
}

private static DatabaseMetaData getMetadataForDbVersion(int major, int minor) throws SQLException {
DatabaseMetaData databaseMetaData = Mockito.mock(DatabaseMetaData.class);
Mockito.when(databaseMetaData.getDatabaseMajorVersion()).thenReturn(major);
Mockito.when(databaseMetaData.getDatabaseMinorVersion()).thenReturn(minor);
return databaseMetaData;
}


@Test
public void index_length_is_not_specified_on_big_varchar_columns() {
verifySql(new CreateIndexBuilder()
.setTable("issues")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(4000).build()),
verifySql(new CreateIndexBuilder(new Oracle())
.setTable("issues")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(4000).build()),
"CREATE INDEX issues_key ON issues (kee)");
}

@Test
public void throw_NPE_if_table_is_missing() {
assertThatThrownBy(() -> {
new CreateIndexBuilder()
new CreateIndexBuilder(new Oracle())
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build())
.build();
@@ -91,7 +146,7 @@ public class CreateIndexBuilderTest {
@Test
public void throw_NPE_if_index_name_is_missing() {
assertThatThrownBy(() -> {
new CreateIndexBuilder()
new CreateIndexBuilder(new H2())
.setTable("issues")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build())
.build();
@@ -103,7 +158,7 @@ public class CreateIndexBuilderTest {
@Test
public void throw_IAE_if_columns_are_missing() {
assertThatThrownBy(() -> {
new CreateIndexBuilder()
new CreateIndexBuilder(new H2())
.setTable("issues")
.setName("issues_key")
.build();
@@ -115,7 +170,7 @@ public class CreateIndexBuilderTest {
@Test
public void throw_IAE_if_table_name_is_not_valid() {
assertThatThrownBy(() -> {
new CreateIndexBuilder()
new CreateIndexBuilder(new H2())
.setTable("(not valid)")
.setName("issues_key")
.addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(10).build())
@@ -128,7 +183,7 @@ public class CreateIndexBuilderTest {
@Test
public void throw_NPE_when_adding_null_column() {
assertThatThrownBy(() -> {
new CreateIndexBuilder()
new CreateIndexBuilder(new H2())
.setTable("issues")
.setName("issues_key")
.addColumn((String) null)

+ 4
- 4
server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/GroupPermissionChangerIT.java 查看文件

@@ -279,9 +279,9 @@ public class GroupPermissionChangerIT {
public void do_nothing_when_adding_permission_that_already_exists() {
db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);

apply(new GroupPermissionChange(Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService));
apply(new GroupPermissionChange(Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService), ADMINISTER_QUALITY_GATES.getKey());

assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
assertThat(db.users().selectGroupPermissions(group, null)).containsExactly(ADMINISTER_QUALITY_GATES.getKey());
}

@Test
@@ -295,7 +295,7 @@ public class GroupPermissionChangerIT {
fail("a BadRequestException should have been thrown for permission " + perm);
} catch (BadRequestException e) {
assertThat(e).hasMessage("Invalid project permission '" + perm +
"'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]");
"'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]");
}
});
}
@@ -311,7 +311,7 @@ public class GroupPermissionChangerIT {
fail("a BadRequestException should have been thrown for permission " + perm);
} catch (BadRequestException e) {
assertThat(e).hasMessage("Invalid project permission '" + perm +
"'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]");
"'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]");
}
});
}

正在加载...
取消
保存