From ea8ca620bf1792afe96bdcf2b24b943fa812a415 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 9 Dec 2016 17:34:02 +0100 Subject: [PATCH] SONAR-8445 fork BaseDataChange and DdlChange in sonar-db-migration interface DataChange is dropped and BaseDataChange renamed to DataChange --- .../db/migration/step/DataChange.java | 89 ++++ .../platform/db/migration/step/DdlChange.java | 121 +++++ .../db/migration/step/DataChangeTest.java | 477 ++++++++++++++++++ .../DataChangeTest/batch-insert-result.xml | 8 + .../step/DataChangeTest/insert-result.xml | 7 + .../DataChangeTest/mass-update-result.xml | 5 + .../migration/step/DataChangeTest/persons.xml | 5 + .../migration/step/DataChangeTest/schema.sql | 8 + .../scroll-and-update-result.xml | 5 + .../DataChangeTest/update-null-result.xml | 5 + .../java/org/sonar/db/version/MassUpdate.java | 2 +- .../java/org/sonar/db/version/SelectImpl.java | 4 +- .../java/org/sonar/db/version/UpsertImpl.java | 2 +- 13 files changed, 734 insertions(+), 4 deletions(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DdlChange.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/step/DataChangeTest.java create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/batch-insert-result.xml create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/insert-result.xml create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/mass-update-result.xml create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/persons.xml create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/schema.sql create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/scroll-and-update-result.xml create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/update-null-result.xml diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java new file mode 100644 index 00000000000..7f254c051f7 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.step; + +import java.sql.Connection; +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.MassUpdate; +import org.sonar.db.version.Select; +import org.sonar.db.version.SelectImpl; +import org.sonar.db.version.Upsert; +import org.sonar.db.version.UpsertImpl; + +public abstract class DataChange implements MigrationStep { + + private final Database db; + + public DataChange(Database db) { + this.db = db; + } + + @Override + public final void execute() throws SQLException { + try (Connection readConnection = createReadUncommittedConnection(); + Connection writeConnection = createDdlConnection()) { + Context context = new Context(db, readConnection, writeConnection); + execute(context); + } + } + + protected abstract void execute(Context context) throws SQLException; + + private Connection createReadUncommittedConnection() throws SQLException { + Connection connection = db.getDataSource().getConnection(); + connection.setAutoCommit(false); + if (connection.getMetaData().supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)) { + connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); + } + return connection; + } + + private Connection createDdlConnection() throws SQLException { + Connection res = db.getDataSource().getConnection(); + res.setAutoCommit(false); + return res; + } + + public static class Context { + private final Database db; + private final Connection readConnection; + private final Connection writeConnection; + + public Context(Database db, Connection readConnection, Connection writeConnection) { + this.db = db; + this.readConnection = readConnection; + this.writeConnection = writeConnection; + } + + public Select prepareSelect(String sql) throws SQLException { + return SelectImpl.create(db, readConnection, sql); + } + + public Upsert prepareUpsert(String sql) throws SQLException { + return UpsertImpl.create(writeConnection, sql); + } + + public MassUpdate prepareMassUpdate() throws SQLException { + return new MassUpdate(db, readConnection, writeConnection); + } + } + +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DdlChange.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DdlChange.java new file mode 100644 index 00000000000..adf259d702a --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DdlChange.java @@ -0,0 +1,121 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.step; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import java.util.regex.Pattern; +import org.sonar.db.Database; +import org.sonar.db.dialect.Dialect; + +import static java.lang.String.format; +import static java.util.Arrays.asList; + +public abstract class DdlChange implements MigrationStep { + + private final Database db; + + public DdlChange(Database db) { + this.db = db; + } + + @Override + public final void execute() throws SQLException { + try (Connection writeConnection = createDdlConnection()) { + Context context = new Context(writeConnection); + execute(context); + } + } + + private Connection createDdlConnection() throws SQLException { + Connection writeConnection = db.getDataSource().getConnection(); + writeConnection.setAutoCommit(false); + return writeConnection; + } + + public abstract void execute(Context context) throws SQLException; + + protected Database getDatabase() { + return db; + } + + protected Dialect getDialect() { + return db.getDialect(); + } + + public static class Context { + private static final int ERROR_HANDLING_THRESHOLD = 10; + // the tricky regexp is required to match "NULL" but not "NOT NULL" + private final Pattern nullPattern = Pattern.compile("\\h?(? 0) { + return format("Fail to execute %s %n (caught %s error, original was %s)", sql, errorCount, original); + } else { + return format("Fail to execute %s", sql); + } + } + + public void execute(String... sqls) throws SQLException { + execute(asList(sqls)); + } + + public void execute(List sqls) throws SQLException { + for (String sql : sqls) { + execute(sql); + } + } + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/step/DataChangeTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/step/DataChangeTest.java new file mode 100644 index 00000000000..f34646f2f1c --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/step/DataChangeTest.java @@ -0,0 +1,477 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.step; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.BatchSession; +import org.sonar.db.DbTester; +import org.sonar.db.version.MassUpdate; +import org.sonar.db.version.Select; +import org.sonar.db.version.Select.Row; +import org.sonar.db.version.Select.RowReader; +import org.sonar.db.version.SqlStatement; +import org.sonar.db.version.Upsert; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + + +public class DataChangeTest { + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, DataChangeTest.class, "schema.sql"); + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() { + db.executeUpdateSql("truncate table persons"); + } + + @Test + public void query() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + final AtomicBoolean executed = new AtomicBoolean(false); + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + assertThat(context.prepareSelect("select id from persons order by id desc").list(Select.LONG_READER)) + .containsExactly(3L, 2L, 1L); + assertThat(context.prepareSelect("select id from persons where id=?").setLong(1, 2L).get(Select.LONG_READER)) + .isEqualTo(2L); + assertThat(context.prepareSelect("select id from persons where id=?").setLong(1, 12345L).get(Select.LONG_READER)) + .isNull(); + executed.set(true); + } + }.execute(); + assertThat(executed.get()).isTrue(); + } + + @Test + public void read_column_types() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + final List persons = new ArrayList<>(); + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + persons.addAll(context + .prepareSelect("select id,login,age,enabled,updated_at,coeff from persons where id=2") + .list(new UserReader())); + } + }.execute(); + assertThat(persons).hasSize(1); + assertThat(persons.get(0)[0]).isEqualTo(2L); + assertThat(persons.get(0)[1]).isEqualTo("emmerik"); + assertThat(persons.get(0)[2]).isEqualTo(14); + assertThat(persons.get(0)[3]).isEqualTo(true); + assertThat(persons.get(0)[4]).isNotNull(); + assertThat(persons.get(0)[5]).isEqualTo(5.2); + } + + @Test + public void parameterized_query() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + final List ids = new ArrayList<>(); + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + ids.addAll(context.prepareSelect("select id from persons where id>=?").setLong(1, 2L).list(Select.LONG_READER)); + } + }.execute(); + assertThat(ids).containsOnly(2L, 3L); + } + + @Test + public void display_current_row_details_if_error_during_get() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Error during processing of row: [id=2]"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + context.prepareSelect("select id from persons where id>=?").setLong(1, 2L).get(new RowReader() { + @Override + public Long read(Row row) throws SQLException { + throw new IllegalStateException("Unexpected error"); + } + }); + } + }.execute(); + + } + + @Test + public void display_current_row_details_if_error_during_list() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Error during processing of row: [id=2]"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + context.prepareSelect("select id from persons where id>=?").setLong(1, 2L).list(new RowReader() { + @Override + public Long read(Row row) throws SQLException { + throw new IllegalStateException("Unexpected error"); + } + }); + } + }.execute(); + + } + + @Test + public void bad_parameterized_query() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + final List ids = new ArrayList<>(); + DataChange change = new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + // parameter value is not set + ids.addAll(context.prepareSelect("select id from persons where id>=?").list(Select.LONG_READER)); + } + }; + + thrown.expect(SQLException.class); + + change.execute(); + } + + @Test + public void scroll() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + final List ids = new ArrayList<>(); + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + context.prepareSelect("select id from persons order by id desc").scroll(new Select.RowHandler() { + @Override + public void handle(Row row) throws SQLException { + ids.add(row.getNullableLong(1)); + } + }); + } + }.execute(); + assertThat(ids).containsExactly(3L, 2L, 1L); + } + + @Test + public void insert() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + context.prepareUpsert("insert into persons(id,login,age,enabled,coeff) values (?,?,?,?,?)") + .setLong(1, 10L) + .setString(2, "kurt") + .setInt(3, 27) + .setBoolean(4, true) + .setDouble(5, 2.2) + .execute().commit().close(); + } + }.execute(); + + db.assertDbUnit(getClass(), "insert-result.xml", "persons"); + } + + @Test + public void batch_insert() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + Upsert upsert = context.prepareUpsert("insert into persons(id,login,age,enabled,coeff) values (?,?,?,?,?)"); + upsert + .setLong(1, 10L) + .setString(2, "kurt") + .setInt(3, 27) + .setBoolean(4, true) + .setDouble(5, 2.2) + .addBatch(); + upsert + .setLong(1, 11L) + .setString(2, "courtney") + .setInt(3, 25) + .setBoolean(4, false) + .setDouble(5, 2.3) + .addBatch(); + upsert.execute().commit().close(); + } + }.execute(); + + db.assertDbUnit(getClass(), "batch-insert-result.xml", "persons"); + } + + @Test + public void update_null() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + Upsert upsert = context.prepareUpsert("update persons set login=?,age=?,enabled=?, updated_at=?, coeff=? where id=?"); + upsert + .setString(1, null) + .setInt(2, null) + .setBoolean(3, null) + .setDate(4, null) + .setDouble(5, null) + .setLong(6, 2L) + .execute() + .commit() + .close(); + } + }.execute(); + + db.assertDbUnit(getClass(), "update-null-result.xml", "persons"); + } + + @Test + public void mass_batch_insert() throws Exception { + db.executeUpdateSql("truncate table persons"); + + final int count = BatchSession.MAX_BATCH_SIZE + 10; + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + Upsert upsert = context.prepareUpsert("insert into persons(id,login,age,enabled,coeff) values (?,?,?,?,?)"); + for (int i = 0; i < count; i++) { + upsert + .setLong(1, 10L + i) + .setString(2, "login" + i) + .setInt(3, 10 + i) + .setBoolean(4, true) + .setDouble(4, i + 0.5) + .addBatch(); + } + upsert.execute().commit().close(); + + } + }.execute(); + + assertThat(db.countRowsOfTable("persons")).isEqualTo(count); + } + + @Test + public void scroll_and_update() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + final Upsert upsert = context.prepareUpsert("update persons set login=?, age=? where id=?"); + context.prepareSelect("select id from persons").scroll(new Select.RowHandler() { + @Override + public void handle(Row row) throws SQLException { + long id = row.getNullableLong(1); + upsert.setString(1, "login" + id).setInt(2, 10 + (int) id).setLong(3, id); + upsert.execute(); + } + }); + upsert.commit().close(); + } + }.execute(); + + db.assertDbUnit(getClass(), "scroll-and-update-result.xml", "persons"); + } + + @Test + public void display_current_row_details_if_error_during_scroll() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Error during processing of row: [id=1]"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + final Upsert upsert = context.prepareUpsert("update persons set login=?, age=? where id=?"); + context.prepareSelect("select id from persons").scroll(new Select.RowHandler() { + @Override + public void handle(Row row) throws SQLException { + throw new IllegalStateException("Unexpected error"); + } + }); + upsert.commit().close(); + } + }.execute(); + } + + @Test + public void mass_update() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("select id from persons where id>=?").setLong(1, 2L); + massUpdate.update("update persons set login=?, age=? where id=?"); + massUpdate.execute(new MassUpdate.Handler() { + @Override + public boolean handle(Row row, SqlStatement update) throws SQLException { + long id = row.getNullableLong(1); + update + .setString(1, "login" + id) + .setInt(2, 10 + (int) id) + .setLong(3, id); + return true; + } + }); + } + }.execute(); + + db.assertDbUnit(getClass(), "mass-update-result.xml", "persons"); + } + + @Test + public void display_current_row_details_if_error_during_mass_update() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Error during processing of row: [id=2]"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("select id from persons where id>=?").setLong(1, 2L); + massUpdate.update("update persons set login=?, age=? where id=?"); + massUpdate.execute(new MassUpdate.Handler() { + @Override + public boolean handle(Row row, SqlStatement update) throws SQLException { + throw new IllegalStateException("Unexpected error"); + } + }); + } + }.execute(); + } + + @Test + public void mass_update_nothing() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("select id from persons where id>=?").setLong(1, 2L); + massUpdate.update("update persons set login=?, age=? where id=?"); + massUpdate.execute(new MassUpdate.Handler() { + @Override + public boolean handle(Row row, SqlStatement update) throws SQLException { + return false; + } + }); + } + }.execute(); + + db.assertDbUnit(getClass(), "persons.xml", "persons"); + } + + @Test + public void bad_mass_update() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + DataChange change = new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("select id from persons where id>=?").setLong(1, 2L); + // update is not set + massUpdate.execute(new MassUpdate.Handler() { + @Override + public boolean handle(Row row, SqlStatement update) throws SQLException { + return false; + } + }); + } + }; + try { + change.execute(); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("SELECT or UPDATE requests are not defined"); + } + } + + @Test + public void read_not_null_fields() throws Exception { + db.prepareDbUnit(getClass(), "persons.xml"); + + final List persons = new ArrayList<>(); + new DataChange(db.database()) { + @Override + public void execute(Context context) throws SQLException { + persons.addAll(context + .prepareSelect("select id,login,age,enabled,updated_at,coeff from persons where id=2") + .list(row -> new Object[] { + // id, login, age, enabled + row.getLong(1), + row.getString(2), + row.getInt(3), + row.getBoolean(4), + row.getDate(5), + row.getDouble(6), + })); + } + }.execute(); + assertThat(persons).hasSize(1); + assertThat(persons.get(0)[0]).isEqualTo(2L); + assertThat(persons.get(0)[1]).isEqualTo("emmerik"); + assertThat(persons.get(0)[2]).isEqualTo(14); + assertThat(persons.get(0)[3]).isEqualTo(true); + assertThat(persons.get(0)[4]).isNotNull(); + assertThat(persons.get(0)[5]).isEqualTo(5.2); + } + + static class UserReader implements RowReader { + @Override + public Object[] read(Row row) throws SQLException { + return new Object[] { + // id, login, age, enabled + row.getNullableLong(1), + row.getNullableString(2), + row.getNullableInt(3), + row.getNullableBoolean(4), + row.getNullableDate(5), + row.getNullableDouble(6), + }; + } + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/batch-insert-result.xml b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/batch-insert-result.xml new file mode 100644 index 00000000000..96ecbf4062f --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/batch-insert-result.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/insert-result.xml b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/insert-result.xml new file mode 100644 index 00000000000..32b7ac03f06 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/insert-result.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/mass-update-result.xml b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/mass-update-result.xml new file mode 100644 index 00000000000..9eb2317febf --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/mass-update-result.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/persons.xml b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/persons.xml new file mode 100644 index 00000000000..62c226d53b7 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/persons.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/schema.sql new file mode 100644 index 00000000000..499b25b599d --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE "PERSONS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "LOGIN" VARCHAR(50), + "AGE" INTEGER, + "ENABLED" BOOLEAN, + "UPDATED_AT" TIMESTAMP, + "COEFF" DOUBLE +); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/scroll-and-update-result.xml b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/scroll-and-update-result.xml new file mode 100644 index 00000000000..0cf4e593d4d --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/scroll-and-update-result.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/update-null-result.xml b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/update-null-result.xml new file mode 100644 index 00000000000..ec48c899b40 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/step/DataChangeTest/update-null-result.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/sonar-db/src/main/java/org/sonar/db/version/MassUpdate.java b/sonar-db/src/main/java/org/sonar/db/version/MassUpdate.java index 4b88f34325b..5218fb7523d 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/MassUpdate.java +++ b/sonar-db/src/main/java/org/sonar/db/version/MassUpdate.java @@ -61,7 +61,7 @@ public class MassUpdate { private Select select; private List updates = new ArrayList<>(1); - MassUpdate(Database db, Connection readConnection, Connection writeConnection) { + public MassUpdate(Database db, Connection readConnection, Connection writeConnection) { this.db = db; this.readConnection = readConnection; this.writeConnection = writeConnection; diff --git a/sonar-db/src/main/java/org/sonar/db/version/SelectImpl.java b/sonar-db/src/main/java/org/sonar/db/version/SelectImpl.java index 19f49d36ba1..ade81249bb6 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/SelectImpl.java +++ b/sonar-db/src/main/java/org/sonar/db/version/SelectImpl.java @@ -28,7 +28,7 @@ import java.util.List; import org.apache.commons.dbutils.DbUtils; import org.sonar.db.Database; -class SelectImpl extends BaseSqlStatementimplements Select { private SelectImpl(PreparedStatement pstmt) { super(pstmt); @@ -89,7 +89,7 @@ class SelectImpl extends BaseSqlStatement