]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7697 Replace integer `purged_status` column with boolean `purged`
authorJacek Poreda <jacek.poreda@sonarsource.com>
Thu, 20 Jul 2023 11:35:09 +0000 (13:35 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 21 Jul 2023 20:03:17 +0000 (20:03 +0000)
17 files changed:
server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java
server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
server/sonar-db-dao/src/schema/schema-sq.ddl
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshots.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/DbVersion102.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshots.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshots.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshots.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshotsTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshotsTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshotsTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshotsTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshotsTest/schema.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshotsTest/schema.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshotsTest/schema.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshotsTest/schema.sql [new file with mode: 0644]

index ec0bb78cd87cafb9e9e26ae6dfe1fe7518cc59ed..b8182de0987a711c3782e0c4e415435ecb2b52f8 100644 (file)
@@ -71,6 +71,7 @@ import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.component.ProjectData;
 import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.dialect.Dialect;
 import org.sonar.db.event.EventComponentChangeDto;
 import org.sonar.db.event.EventDto;
 import org.sonar.db.event.EventTesting;
@@ -100,7 +101,6 @@ import static java.util.Collections.singletonList;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
-import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.only;
 import static org.mockito.Mockito.verify;
@@ -141,7 +141,8 @@ public class PurgeDaoIT {
     db.components().insertSnapshot(project.getMainBranchComponent(), t -> t.setStatus(STATUS_UNPROCESSED).setLast(false));
     SnapshotDto lastAnalysis = db.components().insertSnapshot(project.getMainBranchComponent(), t -> t.setStatus(STATUS_PROCESSED).setLast(true));
 
-    underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.getMainBranchComponent().uuid(), project.projectUuid()), PurgeListener.EMPTY, new PurgeProfiler());
+    underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.getMainBranchComponent().uuid(), project.projectUuid()), PurgeListener.EMPTY,
+      new PurgeProfiler());
     dbSession.commit();
 
     assertThat(uuidsOfAnalysesOfRoot(project.getMainBranchComponent())).containsOnly(pastAnalysis.getUuid(), lastAnalysis.getUuid());
@@ -198,9 +199,11 @@ public class PurgeDaoIT {
     BranchDto pr3 = db.components().insertProjectBranch(project.getProjectDto(), b -> b.setBranchType(BranchType.PULL_REQUEST).setExcludeFromPurge(true));
     addComponentsSnapshotsAndIssuesToBranch(pr3, rule, 100);
 
-    updateBranchCreationDate(date31DaysAgo, branch1.getUuid(), branch2.getUuid(), branch3.getUuid(), branch4.getUuid(), branch5.getUuid(), pr1.getUuid(), pr2.getUuid(), pr3.getUuid());
+    updateBranchCreationDate(date31DaysAgo, branch1.getUuid(), branch2.getUuid(), branch3.getUuid(), branch4.getUuid(), branch5.getUuid(), pr1.getUuid(), pr2.getUuid(),
+      pr3.getUuid());
 
-    underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.getMainBranchDto().getUuid(), project.getProjectDto().getUuid()), PurgeListener.EMPTY, new PurgeProfiler());
+    underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.getMainBranchDto().getUuid(), project.getProjectDto().getUuid()), PurgeListener.EMPTY,
+      new PurgeProfiler());
     dbSession.commit();
 
     assertThat(uuidsIn("components")).containsOnly(
@@ -232,7 +235,8 @@ public class PurgeDaoIT {
     ComponentDto file = db.components().insertComponent(newFileDto(pullRequestComponent, dir));
     db.issues().insert(rule, pullRequestComponent, file);
 
-    underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.getMainBranchComponent().branchUuid(), project.getProjectDto().getUuid()), PurgeListener.EMPTY, new PurgeProfiler());
+    underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.getMainBranchComponent().branchUuid(), project.getProjectDto().getUuid()), PurgeListener.EMPTY,
+      new PurgeProfiler());
     dbSession.commit();
 
     assertThat(uuidsIn("components")).containsOnly(project.getMainBranchDto().getUuid(), nonMainBranch.getUuid(), recentPullRequest.getUuid());
@@ -296,7 +300,7 @@ public class PurgeDaoIT {
     IssueDto openOnEnabledComponent = db.issues().insert(rule, mainBranch, enabledFile, issue -> issue.setStatus("OPEN"));
     IssueDto confirmOnEnabledComponent = db.issues().insert(rule, mainBranch, enabledFile, issue -> issue.setStatus("CONFIRM"));
 
-    assertThat(db.countSql("select count(*) from snapshots where purge_status = 1")).isZero();
+    assertThat(countPurgedSnapshots()).isZero();
 
     assertThat(db.countSql("select count(*) from issues where status = 'CLOSED'")).isZero();
     assertThat(db.countSql("select count(*) from issues where resolution = 'REMOVED'")).isZero();
@@ -324,8 +328,8 @@ public class PurgeDaoIT {
       purgeListener, new PurgeProfiler());
     dbSession.commit();
 
-    // set purge_status=1 for non-last snapshot
-    assertThat(db.countSql("select count(*) from snapshots where purge_status = 1")).isOne();
+    // set purged=true for non-last snapshot
+    assertThat(countPurgedSnapshots()).isOne();
 
     // close open issues of selected
     assertThat(db.countSql("select count(*) from issues where status = 'CLOSED'")).isEqualTo(4);
@@ -696,10 +700,12 @@ public class PurgeDaoIT {
     underTest.deleteBranch(dbSession, appBranch.getUuid());
     dbSession.commit();
 
-    assertThat(uuidsIn("components")).containsOnly(project.getMainBranchDto().getUuid(), app.getMainBranchDto().getUuid(), otherApp.getMainBranchDto().getUuid(), otherAppBranch.getUuid());
+    assertThat(uuidsIn("components")).containsOnly(project.getMainBranchDto().getUuid(), app.getMainBranchDto().getUuid(), otherApp.getMainBranchDto().getUuid(),
+      otherAppBranch.getUuid());
     assertThat(uuidsIn("projects")).containsOnly(project.getProjectDto().getUuid(), app.getProjectDto().getUuid(), otherApp.getProjectDto().getUuid());
     assertThat(uuidsIn("snapshots")).containsOnly(otherAppAnalysis.getUuid(), appAnalysis.getUuid(), otherAppBranchAnalysis.getUuid());
-    assertThat(uuidsIn("project_branches")).containsOnly(project.getMainBranchDto().getUuid(), app.getMainBranchDto().getUuid(), otherApp.getMainBranchDto().getUuid(), otherAppBranch.getUuid());
+    assertThat(uuidsIn("project_branches")).containsOnly(project.getMainBranchDto().getUuid(), app.getMainBranchDto().getUuid(), otherApp.getMainBranchDto().getUuid(),
+      otherAppBranch.getUuid());
     assertThat(uuidsIn("project_measures")).containsOnly(appMeasure.getUuid(), otherAppMeasure.getUuid(), otherAppBranchMeasure.getUuid());
     assertThat(uuidsIn("app_projects", "application_uuid")).containsOnly(app.getProjectDto().getUuid(), otherApp.getProjectDto().getUuid());
     assertThat(uuidsIn("app_branch_project_branch", "application_branch_uuid")).containsOnly(otherAppBranch.getUuid());
@@ -775,7 +781,6 @@ public class PurgeDaoIT {
     ComponentDto anotherBranch = db.components().insertProjectBranch(project.getMainBranchComponent());
     ProjectData anotherProject = db.components().insertPrivateProject();
 
-
     CeActivityDto projectTask = insertCeActivity(project.getMainBranchComponent(), project.getProjectDto().getUuid());
     insertCeTaskInput(projectTask.getUuid());
     CeActivityDto branchTask = insertCeActivity(branch, project.getProjectDto().getUuid());
@@ -793,7 +798,8 @@ public class PurgeDaoIT {
     assertThat(uuidsIn("ce_activity")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid());
     assertThat(taskUuidsIn("ce_task_input")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid(), "non existing task");
 
-    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(), project.getProjectDto().getKey());
+    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(),
+      project.getProjectDto().getKey());
     dbSession.commit();
 
     assertThat(uuidsIn("ce_activity")).containsOnly(anotherProjectTask.getUuid());
@@ -824,7 +830,8 @@ public class PurgeDaoIT {
     assertThat(uuidsIn("ce_activity")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid());
     assertThat(taskUuidsIn("ce_scanner_context")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid(), "non existing task");
 
-    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(), project.getProjectDto().getKey());
+    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(),
+      project.getProjectDto().getKey());
     dbSession.commit();
 
     assertThat(uuidsIn("ce_activity")).containsOnly(anotherProjectTask.getUuid());
@@ -838,7 +845,6 @@ public class PurgeDaoIT {
     ComponentDto anotherBranch = db.components().insertProjectBranch(project.getMainBranchComponent());
     ProjectData anotherProject = db.components().insertPrivateProject();
 
-
     CeActivityDto projectTask = insertCeActivity(project.getMainBranchComponent(), project.projectUuid());
     insertCeTaskCharacteristics(projectTask.getUuid(), 3);
     CeActivityDto branchTask = insertCeActivity(branch, project.projectUuid());
@@ -856,7 +862,8 @@ public class PurgeDaoIT {
     assertThat(uuidsIn("ce_activity")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid());
     assertThat(taskUuidsIn("ce_task_characteristics")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid(), "non existing task");
 
-    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(), project.getProjectDto().getKey());
+    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(),
+      project.getProjectDto().getKey());
     dbSession.commit();
 
     assertThat(uuidsIn("ce_activity")).containsOnly(anotherProjectTask.getUuid());
@@ -887,7 +894,8 @@ public class PurgeDaoIT {
     assertThat(uuidsIn("ce_activity")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid());
     assertThat(taskUuidsIn("ce_task_message")).containsOnly(projectTask.getUuid(), anotherBranchTask.getUuid(), anotherProjectTask.getUuid(), "non existing task");
 
-    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(), project.getProjectDto().getKey());
+    underTest.deleteProject(dbSession, project.getProjectDto().getUuid(), project.getProjectDto().getQualifier(), project.getProjectDto().getName(),
+      project.getProjectDto().getKey());
     dbSession.commit();
 
     assertThat(uuidsIn("ce_activity")).containsOnly(anotherProjectTask.getUuid());
@@ -1602,7 +1610,8 @@ public class PurgeDaoIT {
     verifyNoEffect(componentDbTester.insertPrivateProject().getMainBranchComponent());
     verifyNoEffect(componentDbTester.insertPublicProject().getMainBranchComponent());
     verifyNoEffect(componentDbTester.insertPrivatePortfolio());
-    verifyNoEffect(componentDbTester.insertPrivatePortfolio(), componentDbTester.insertPrivateProject().getMainBranchComponent(), componentDbTester.insertPublicProject().getMainBranchComponent());
+    verifyNoEffect(componentDbTester.insertPrivatePortfolio(), componentDbTester.insertPrivateProject().getMainBranchComponent(),
+      componentDbTester.insertPublicProject().getMainBranchComponent());
   }
 
   @Test
@@ -1637,7 +1646,8 @@ public class PurgeDaoIT {
 
   @Test
   public void deleteNonRootComponents_deletes_only_non_root_components_of_a_project_from_table_components() {
-    ComponentDto project = new Random().nextBoolean() ? db.components().insertPublicProject().getMainBranchComponent() : db.components().insertPrivateProject().getMainBranchComponent();
+    ComponentDto project = new Random().nextBoolean() ? db.components().insertPublicProject().getMainBranchComponent()
+      : db.components().insertPrivateProject().getMainBranchComponent();
     ComponentDto dir1 = db.components().insertComponent(newDirectory(project, "A/B"));
     ComponentDto file1 = db.components().insertComponent(newFileDto(project, dir1));
 
@@ -1684,7 +1694,8 @@ public class PurgeDaoIT {
 
   @Test
   public void deleteNonRootComponents_deletes_only_specified_non_root_components_of_a_project_from_table_components() {
-    ComponentDto project = new Random().nextBoolean() ? db.components().insertPublicProject().getMainBranchComponent() : db.components().insertPrivateProject().getMainBranchComponent();
+    ComponentDto project = new Random().nextBoolean() ? db.components().insertPublicProject().getMainBranchComponent()
+      : db.components().insertPrivateProject().getMainBranchComponent();
     ComponentDto dir1 = db.components().insertComponent(newDirectory(project, "A/B"));
     ComponentDto dir2 = db.components().insertComponent(newDirectory(project, "A/C"));
     ComponentDto file1 = db.components().insertComponent(newFileDto(project, dir1));
@@ -1722,7 +1733,8 @@ public class PurgeDaoIT {
 
     underTest.deleteNonRootComponentsInView(dbSession, asList(subview1, pc2));
     assertThat(uuidsIn("components"))
-      .containsOnly(view.uuid(), projects[0].getMainBranchComponent().uuid(), projects[1].getMainBranchComponent().uuid(), projects[2].getMainBranchComponent().uuid(), subview2.uuid(), pc1.uuid());
+      .containsOnly(view.uuid(), projects[0].getMainBranchComponent().uuid(), projects[1].getMainBranchComponent().uuid(), projects[2].getMainBranchComponent().uuid(),
+        subview2.uuid(), pc1.uuid());
     assertThat(uuidsIn("projects")).containsOnly(projects[0].getProjectDto().getUuid(), projects[1].getProjectDto().getUuid(), projects[2].getProjectDto().getUuid());
   }
 
@@ -1865,17 +1877,17 @@ public class PurgeDaoIT {
 
   private void insertPropertyFor(ComponentDto... components) {
     Stream.of(components).forEach(componentDto -> db.properties().insertProperty(new PropertyDto()
-        .setKey(randomAlphabetic(3))
-        .setValue(randomAlphabetic(3))
-        .setEntityUuid(componentDto.uuid()),
+      .setKey(randomAlphabetic(3))
+      .setValue(randomAlphabetic(3))
+      .setEntityUuid(componentDto.uuid()),
       componentDto.getKey(), componentDto.name(), componentDto.qualifier(), null));
   }
 
   private void insertPropertyFor(Collection<BranchDto> branches) {
     branches.stream().forEach(branchDto -> db.properties().insertProperty(new PropertyDto()
-        .setKey(randomAlphabetic(3))
-        .setValue(randomAlphabetic(3))
-        .setEntityUuid(branchDto.getUuid()),
+      .setKey(randomAlphabetic(3))
+      .setValue(randomAlphabetic(3))
+      .setEntityUuid(branchDto.getUuid()),
       null, branchDto.getKey(), null, null));
   }
 
@@ -2020,4 +2032,10 @@ public class PurgeDaoIT {
     addComponentsSnapshotsAndIssuesToBranch(componentDto, rule, branchAge);
   }
 
+  private int countPurgedSnapshots() {
+    Dialect dialect = db.getDbClient().getDatabase().getDialect();
+    String bool = dialect.getTrueSqlValue();
+    return db.countSql("select count(*) from snapshots where purged = " + bool);
+  }
+
 }
index 1d5fcc6abbd55d9d7a328fa2d845120c46c935d1..4ebbc769fff393033c475c97bd83eacdf81bb8e1 100644 (file)
       period1_mode,
       period1_param,
       period1_date,
-      revision
+      revision,
+      purged
     )
     values (
       #{uuid, jdbcType=VARCHAR},
       #{periodMode, jdbcType=VARCHAR},
       #{periodParam, jdbcType=VARCHAR},
       #{periodDate, jdbcType=BIGINT},
-      #{revision, jdbcType=VARCHAR}
+      #{revision, jdbcType=VARCHAR},
+      ${_false}
     )
   </insert>
 </mapper>
index 79987cf193a3bc27ad76d00809f40ff9afd475a3..770955921ca01a20c562afb4d0744bd155187f40 100644 (file)
@@ -14,7 +14,7 @@
         and s.islast=#{islast}
       </if>
       <if test="notPurged != null and notPurged">
-        and (s.purge_status is null or s.purge_status=0)
+        and s.purged = ${_false}
       </if>
       <if test="status != null">
         and s.status in
     update
       snapshots
     set
-      purge_status = 1
+      purged = ${_true}
     where
       uuid in
       <foreach collection="analysisUuids" open="(" close=")" item="analysisUuid" separator=",">
index 4d9d6560ed1bb1760f8e6a17f139d646f11ea809..46f7cdb381d315762f1f6a5fe47204036082d372 100644 (file)
@@ -967,14 +967,14 @@ CREATE TABLE "SNAPSHOTS"(
     "STATUS" CHARACTER VARYING(4) DEFAULT 'U' NOT NULL,
     "ISLAST" BOOLEAN DEFAULT FALSE NOT NULL,
     "VERSION" CHARACTER VARYING(500),
-    "PURGE_STATUS" INTEGER,
     "BUILD_STRING" CHARACTER VARYING(100),
     "REVISION" CHARACTER VARYING(100),
     "BUILD_DATE" BIGINT,
     "PERIOD1_MODE" CHARACTER VARYING(100),
     "PERIOD1_PARAM" CHARACTER VARYING(100),
     "PERIOD1_DATE" BIGINT,
-    "CREATED_AT" BIGINT
+    "CREATED_AT" BIGINT,
+    "PURGED" BOOLEAN NOT NULL
 );
 ALTER TABLE "SNAPSHOTS" ADD CONSTRAINT "PK_SNAPSHOTS" PRIMARY KEY("UUID");
 CREATE INDEX "SNAPSHOTS_ROOT_COMPONENT_UUID" ON "SNAPSHOTS"("ROOT_COMPONENT_UUID" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshots.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshots.java
new file mode 100644 (file)
index 0000000..e2d2e48
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.def.BooleanColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class CreateBooleanPurgedColumnInSnapshots extends DdlChange {
+  private static final String COLUMN_NAME = "purged";
+  private static final String TABLE_NAME = "snapshots";
+
+  public CreateBooleanPurgedColumnInSnapshots(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    if (checkIfColumnExists()) {
+      return;
+    }
+    BooleanColumnDef columnDef = BooleanColumnDef.newBooleanColumnDefBuilder(COLUMN_NAME).setIsNullable(true).build();
+    context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME).addColumn(columnDef).build());
+  }
+
+  public boolean checkIfColumnExists() throws SQLException {
+    try (var connection = getDatabase().getDataSource().getConnection()) {
+      if (DatabaseUtils.tableColumnExists(connection, TABLE_NAME, COLUMN_NAME)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
index 39ccad83e792cdc18c403f791c8bdeeaa0dbcd4e..cd6bfeb4d7eed80519c948199e66c86475640abd 100644 (file)
@@ -70,6 +70,11 @@ public class DbVersion102 implements DbVersion {
       .add(10_2_018, "Drop index 'component_uuid' in 'snapshots' table", DropIndexComponentUuidInSnapshots.class)
       .add(10_2_019, "Rename 'component_uuid' in 'snapshots' table to 'root_component_uuid'", RenameComponentUuidInSnapshots.class)
       .add(10_2_020, "Create index 'snapshots_root_component_uuid' in 'snapshots' table", CreateIndexRootComponentUuidInSnapshots.class)
+
+      .add(10_2_021, "Create 'purged' column in 'snapshots' table", CreateBooleanPurgedColumnInSnapshots.class)
+      .add(10_2_022, "Populate 'purged' column in 'snapshots' table", PopulatePurgedColumnInSnapshots.class)
+      .add(10_2_023, "Make 'purged' column not nullable in 'snapshots' table", MakePurgedColumnNotNullableInSnapshots.class)
+      .add(10_2_024, "Drop 'purge_status' column in 'snapshots' table", DropPurgeStatusColumnInSnapshots.class)
     ;
   }
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshots.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshots.java
new file mode 100644 (file)
index 0000000..c8aa2ab
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DropColumnChange;
+
+public class DropPurgeStatusColumnInSnapshots extends DropColumnChange {
+  private static final String COLUMN_NAME = "purge_status";
+  private static final String TABLE_NAME = "snapshots";
+
+  public DropPurgeStatusColumnInSnapshots(Database db) {
+    super(db, TABLE_NAME, COLUMN_NAME);
+  }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshots.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshots.java
new file mode 100644 (file)
index 0000000..677f2d4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.BooleanColumnDef;
+import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class MakePurgedColumnNotNullableInSnapshots extends DdlChange {
+  private static final String COLUMN_NAME = "purged";
+  private static final String TABLE_NAME = "snapshots";
+  public MakePurgedColumnNotNullableInSnapshots(Database db) {
+    super(db);
+  }
+  @Override
+  public void execute(Context context) throws SQLException {
+    BooleanColumnDef columnDef = BooleanColumnDef.newBooleanColumnDefBuilder(COLUMN_NAME).setIsNullable(false).build();
+    context.execute(new AlterColumnsBuilder(getDialect(), TABLE_NAME).updateColumn(columnDef).build());
+  }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshots.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshots.java
new file mode 100644 (file)
index 0000000..efdff45
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class PopulatePurgedColumnInSnapshots extends DataChange {
+  private static final String SELECT_QUERY = """
+    SELECT s.uuid, s.purge_status
+    FROM snapshots s
+    WHERE s.purged is null
+    """;
+
+  private static final String UPDATE_QUERY = """
+    UPDATE snapshots
+    SET purged=?
+    WHERE uuid=?
+    """;
+
+  public PopulatePurgedColumnInSnapshots(Database db) {
+    super(db);
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    if (!checkIfColumnExists()) {
+      return;
+    }
+
+    MassUpdate massUpdate = context.prepareMassUpdate();
+    massUpdate.select(SELECT_QUERY);
+    massUpdate.update(UPDATE_QUERY);
+
+    massUpdate.execute((row, update, index) -> {
+      String snapshotUuid = row.getString(1);
+      Integer purgedStatus = row.getNullableInt(2);
+      update.setBoolean(1, purgedStatus != null && purgedStatus == 1)
+        .setString(2, snapshotUuid);
+      return true;
+    });
+  }
+
+  public boolean checkIfColumnExists() throws SQLException {
+    try (var connection = getDatabase().getDataSource().getConnection()) {
+      if (DatabaseUtils.tableColumnExists(connection, "snapshots", "purge_status")) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshotsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshotsTest.java
new file mode 100644 (file)
index 0000000..952a6bd
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BOOLEAN;
+
+public class CreateBooleanPurgedColumnInSnapshotsTest {
+
+  private static final String TABLE_NAME = "snapshots";
+  private static final String COLUMN_NAME = "purged";
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(CreateBooleanPurgedColumnInSnapshotsTest.class, "schema.sql");
+
+  private final CreateBooleanPurgedColumnInSnapshots underTest = new CreateBooleanPurgedColumnInSnapshots(db.database());
+
+  @Test
+  public void execute_whenColumnDoesNotExist_shouldCreatePurgedColumn() throws SQLException {
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+    underTest.execute();
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, null);
+  }
+
+  @Test
+  public void execute_whenExecutedTwice_shouldNotFail() throws SQLException {
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+    underTest.execute();
+    underTest.execute();
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, null);
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshotsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshotsTest.java
new file mode 100644 (file)
index 0000000..cceeff1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class DropPurgeStatusColumnInSnapshotsTest {
+
+  private static final String TABLE_NAME = "snapshots";
+  private static final String COLUMN_NAME = "purge_status";
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(DropPurgeStatusColumnInSnapshotsTest.class, "schema.sql");
+
+  private final DropPurgeStatusColumnInSnapshots underTest = new DropPurgeStatusColumnInSnapshots(db.database());
+
+  @Test
+  public void drops_column() throws SQLException {
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.INTEGER, null, null);
+    underTest.execute();
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+  }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.INTEGER, null, null);
+    underTest.execute();
+    underTest.execute();
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshotsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshotsTest.java
new file mode 100644 (file)
index 0000000..9e857e2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BOOLEAN;
+
+public class MakePurgedColumnNotNullableInSnapshotsTest {
+  private static final String TABLE_NAME = "snapshots";
+  private static final String COLUMN_NAME = "purged";
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(MakePurgedColumnNotNullableInSnapshotsTest.class, "schema.sql");
+
+  private final MakePurgedColumnNotNullableInSnapshots underTest = new MakePurgedColumnNotNullableInSnapshots(db.database());
+
+  @Test
+  public void execute_whenColumnIsNullable_shouldMakeColumnNullable() throws SQLException {
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, true);
+    underTest.execute();
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, false);
+  }
+
+  @Test
+  public void execute_whenExecutedTwice_shouldMakeColumnNullable() throws SQLException {
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, true);
+    underTest.execute();
+    underTest.execute();
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BOOLEAN, null, false);
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshotsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshotsTest.java
new file mode 100644 (file)
index 0000000..f451513
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v102;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class PopulatePurgedColumnInSnapshotsTest {
+  private static final String TABLE_NAME = "snapshots";
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(PopulatePurgedColumnInSnapshotsTest.class, "schema.sql");
+
+  private final PopulatePurgedColumnInSnapshots underTest = new PopulatePurgedColumnInSnapshots(db.database());
+
+  @Test
+  public void execute_whenSnapshotsDoesNotExist_shouldNotFail() {
+    assertThatCode(underTest::execute)
+      .doesNotThrowAnyException();
+  }
+
+  @Test
+  public void execute_whenSnapshotsExist_shouldPopulatePurgedColumn() throws SQLException {
+    insertSnapshot("uuid-1", null);
+    insertSnapshot("uuid-2", 1);
+    insertSnapshot("uuid-3", 0);
+    insertSnapshot("uuid-4", null);
+
+    underTest.execute();
+
+    assertThat(db.select("select UUID, PURGED from snapshots"))
+      .extracting(stringObjectMap -> stringObjectMap.get("UUID"), stringObjectMap -> stringObjectMap.get("PURGED"))
+      .containsExactlyInAnyOrder(
+        tuple("uuid-1", false),
+        tuple("uuid-2", true),
+        tuple("uuid-3", false),
+        tuple("uuid-4", false));
+  }
+
+  private void insertSnapshot(String uuid, @Nullable Integer status) {
+    db.executeInsert(TABLE_NAME,
+      "UUID", uuid,
+      "ROOT_COMPONENT_UUID", "",
+      "STATUS", "",
+      "ISLAST", true,
+      "PURGE_STATUS", status,
+      "PURGED", null);
+  }
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshotsTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/CreateBooleanPurgedColumnInSnapshotsTest/schema.sql
new file mode 100644 (file)
index 0000000..c11248e
--- /dev/null
@@ -0,0 +1,17 @@
+CREATE TABLE "SNAPSHOTS"(
+    "UUID" CHARACTER VARYING(50) NOT NULL,
+    "ROOT_COMPONENT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "STATUS" CHARACTER VARYING(4) DEFAULT 'U' NOT NULL,
+    "ISLAST" BOOLEAN DEFAULT FALSE NOT NULL,
+    "VERSION" CHARACTER VARYING(500),
+    "PURGE_STATUS" INTEGER,
+    "BUILD_STRING" CHARACTER VARYING(100),
+    "REVISION" CHARACTER VARYING(100),
+    "BUILD_DATE" BIGINT,
+    "PERIOD1_MODE" CHARACTER VARYING(100),
+    "PERIOD1_PARAM" CHARACTER VARYING(100),
+    "PERIOD1_DATE" BIGINT,
+    "CREATED_AT" BIGINT
+);
+ALTER TABLE "SNAPSHOTS" ADD CONSTRAINT "PK_SNAPSHOTS" PRIMARY KEY("UUID");
+CREATE INDEX "SNAPSHOTS_ROOT_COMPONENT_UUID" ON "SNAPSHOTS"("ROOT_COMPONENT_UUID" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshotsTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/DropPurgeStatusColumnInSnapshotsTest/schema.sql
new file mode 100644 (file)
index 0000000..c5c483c
--- /dev/null
@@ -0,0 +1,18 @@
+CREATE TABLE "SNAPSHOTS"(
+    "UUID" CHARACTER VARYING(50) NOT NULL,
+    "ROOT_COMPONENT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "STATUS" CHARACTER VARYING(4) DEFAULT 'U' NOT NULL,
+    "ISLAST" BOOLEAN DEFAULT FALSE NOT NULL,
+    "VERSION" CHARACTER VARYING(500),
+    "PURGE_STATUS" INTEGER,
+    "BUILD_STRING" CHARACTER VARYING(100),
+    "REVISION" CHARACTER VARYING(100),
+    "BUILD_DATE" BIGINT,
+    "PERIOD1_MODE" CHARACTER VARYING(100),
+    "PERIOD1_PARAM" CHARACTER VARYING(100),
+    "PERIOD1_DATE" BIGINT,
+    "CREATED_AT" BIGINT,
+    "PURGED" BOOLEAN NOT NULL
+);
+ALTER TABLE "SNAPSHOTS" ADD CONSTRAINT "PK_SNAPSHOTS" PRIMARY KEY("UUID");
+CREATE INDEX "SNAPSHOTS_ROOT_COMPONENT_UUID" ON "SNAPSHOTS"("ROOT_COMPONENT_UUID" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshotsTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/MakePurgedColumnNotNullableInSnapshotsTest/schema.sql
new file mode 100644 (file)
index 0000000..354baa7
--- /dev/null
@@ -0,0 +1,18 @@
+CREATE TABLE "SNAPSHOTS"(
+    "UUID" CHARACTER VARYING(50) NOT NULL,
+    "ROOT_COMPONENT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "STATUS" CHARACTER VARYING(4) DEFAULT 'U' NOT NULL,
+    "ISLAST" BOOLEAN DEFAULT FALSE NOT NULL,
+    "VERSION" CHARACTER VARYING(500),
+    "PURGE_STATUS" INTEGER,
+    "BUILD_STRING" CHARACTER VARYING(100),
+    "REVISION" CHARACTER VARYING(100),
+    "BUILD_DATE" BIGINT,
+    "PERIOD1_MODE" CHARACTER VARYING(100),
+    "PERIOD1_PARAM" CHARACTER VARYING(100),
+    "PERIOD1_DATE" BIGINT,
+    "CREATED_AT" BIGINT,
+    "PURGED" BOOLEAN
+);
+ALTER TABLE "SNAPSHOTS" ADD CONSTRAINT "PK_SNAPSHOTS" PRIMARY KEY("UUID");
+CREATE INDEX "SNAPSHOTS_ROOT_COMPONENT_UUID" ON "SNAPSHOTS"("ROOT_COMPONENT_UUID" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshotsTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/PopulatePurgedColumnInSnapshotsTest/schema.sql
new file mode 100644 (file)
index 0000000..354baa7
--- /dev/null
@@ -0,0 +1,18 @@
+CREATE TABLE "SNAPSHOTS"(
+    "UUID" CHARACTER VARYING(50) NOT NULL,
+    "ROOT_COMPONENT_UUID" CHARACTER VARYING(50) NOT NULL,
+    "STATUS" CHARACTER VARYING(4) DEFAULT 'U' NOT NULL,
+    "ISLAST" BOOLEAN DEFAULT FALSE NOT NULL,
+    "VERSION" CHARACTER VARYING(500),
+    "PURGE_STATUS" INTEGER,
+    "BUILD_STRING" CHARACTER VARYING(100),
+    "REVISION" CHARACTER VARYING(100),
+    "BUILD_DATE" BIGINT,
+    "PERIOD1_MODE" CHARACTER VARYING(100),
+    "PERIOD1_PARAM" CHARACTER VARYING(100),
+    "PERIOD1_DATE" BIGINT,
+    "CREATED_AT" BIGINT,
+    "PURGED" BOOLEAN
+);
+ALTER TABLE "SNAPSHOTS" ADD CONSTRAINT "PK_SNAPSHOTS" PRIMARY KEY("UUID");
+CREATE INDEX "SNAPSHOTS_ROOT_COMPONENT_UUID" ON "SNAPSHOTS"("ROOT_COMPONENT_UUID" NULLS FIRST);