--- /dev/null
+/*
+ * 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.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Date;
+import javax.annotation.Nullable;
+import org.apache.commons.dbutils.DbUtils;
+
+class BaseSqlStatement<CHILD extends SqlStatement> implements SqlStatement<CHILD> {
+ protected PreparedStatement pstmt;
+
+ protected BaseSqlStatement(PreparedStatement pstmt) {
+ this.pstmt = pstmt;
+ }
+
+ @Override
+ public void close() {
+ DbUtils.closeQuietly(pstmt);
+ pstmt = null;
+ }
+
+ @Override
+ public CHILD setString(int columnIndex, @Nullable String value) throws SQLException {
+ pstmt.setString(columnIndex, value);
+ return (CHILD) this;
+ }
+
+ @Override
+ public CHILD setBytes(int columnIndex, @Nullable byte[] value) throws SQLException {
+ pstmt.setBytes(columnIndex, value);
+ return (CHILD) this;
+ }
+
+ @Override
+ public CHILD setInt(int columnIndex, @Nullable Integer value) throws SQLException {
+ if (value == null) {
+ pstmt.setNull(columnIndex, Types.INTEGER);
+ } else {
+ pstmt.setInt(columnIndex, value);
+ }
+ return (CHILD) this;
+ }
+
+ @Override
+ public CHILD setLong(int columnIndex, @Nullable Long value) throws SQLException {
+ if (value == null) {
+ pstmt.setNull(columnIndex, Types.BIGINT);
+ } else {
+ pstmt.setLong(columnIndex, value);
+ }
+ return (CHILD) this;
+ }
+
+ @Override
+ public CHILD setBoolean(int columnIndex, @Nullable Boolean value) throws SQLException {
+ if (value == null) {
+ pstmt.setNull(columnIndex, Types.BOOLEAN);
+ } else {
+ pstmt.setBoolean(columnIndex, value);
+ }
+ return (CHILD) this;
+ }
+
+ @Override
+ public CHILD setDouble(int columnIndex, @Nullable Double value) throws SQLException {
+ if (value == null) {
+ pstmt.setNull(columnIndex, Types.DECIMAL);
+ } else {
+ pstmt.setDouble(columnIndex, value);
+ }
+ return (CHILD) this;
+ }
+
+ @Override
+ public CHILD setDate(int columnIndex, @Nullable Date value) throws SQLException {
+ if (value == null) {
+ pstmt.setNull(columnIndex, Types.TIMESTAMP);
+ } else {
+ pstmt.setTimestamp(columnIndex, new Timestamp(value.getTime()));
+ }
+ return (CHILD) this;
+ }
+}
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 {
--- /dev/null
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import org.sonar.core.util.ProgressLogger;
+import org.sonar.db.Database;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public class MassUpdate {
+
+ @FunctionalInterface
+ public interface Handler {
+ /**
+ * Convert some column values of a given row.
+ *
+ * @return true if the row must be updated, else false. If false, then the update parameter must not be touched.
+ */
+ boolean handle(Select.Row row, SqlStatement update) throws SQLException;
+ }
+
+ @FunctionalInterface
+ public interface MultiHandler {
+ /**
+ * Convert some column values of a given row.
+ *
+ * @param updateIndex 0-based
+ * @return true if the row must be updated, else false. If false, then the update parameter must not be touched.
+ */
+ boolean handle(Select.Row row, SqlStatement update, int updateIndex) throws SQLException;
+ }
+
+ private final Database db;
+ private final Connection readConnection;
+ private final Connection writeConnection;
+ private final AtomicLong counter = new AtomicLong(0L);
+ private final ProgressLogger progress = ProgressLogger.create(getClass(), counter);
+
+ private Select select;
+ private List<UpsertImpl> updates = new ArrayList<>(1);
+
+ public MassUpdate(Database db, Connection readConnection, Connection writeConnection) {
+ this.db = db;
+ this.readConnection = readConnection;
+ this.writeConnection = writeConnection;
+ }
+
+ public SqlStatement select(String sql) throws SQLException {
+ this.select = SelectImpl.create(db, readConnection, sql);
+ return this.select;
+ }
+
+ public MassUpdate update(String sql) throws SQLException {
+ this.updates.add(UpsertImpl.create(writeConnection, sql));
+ return this;
+ }
+
+ public MassUpdate rowPluralName(String s) {
+ this.progress.setPluralLabel(s);
+ return this;
+ }
+
+ public void execute(Handler handler) throws SQLException {
+ checkState(select != null && !updates.isEmpty(), "SELECT or UPDATE requests are not defined");
+ checkState(updates.size() == 1, "There should be only one update when using a " + Handler.class.getName());
+
+ progress.start();
+ try {
+ select.scroll(row -> callSingleHandler(handler, updates.iterator().next(), row));
+ closeUpdates();
+
+ // log the total number of processed rows
+ progress.log();
+ } finally {
+ progress.stop();
+ }
+ }
+
+ public void execute(MultiHandler handler) throws SQLException {
+ checkState(select != null && !updates.isEmpty(), "SELECT or UPDATE(s) requests are not defined");
+
+ progress.start();
+ try {
+ select.scroll(row -> callMultiHandler(handler, updates, row));
+ closeUpdates();
+
+ // log the total number of processed rows
+ progress.log();
+ } finally {
+ progress.stop();
+ }
+ }
+
+ private void callSingleHandler(Handler handler, Upsert update, Select.Row row) throws SQLException {
+ if (handler.handle(row, update)) {
+ update.addBatch();
+ }
+ counter.getAndIncrement();
+ }
+
+ private void callMultiHandler(MultiHandler handler, List<UpsertImpl> updates, Select.Row row) throws SQLException {
+ int i = 0;
+ for (UpsertImpl update : updates) {
+ if (handler.handle(row, update, i)) {
+ update.addBatch();
+ }
+ i++;
+ }
+ counter.getAndIncrement();
+ }
+
+ private void closeUpdates() throws SQLException {
+ for (UpsertImpl update : updates) {
+ if (update.getBatchCount() > 0L) {
+ update.execute().commit();
+ }
+ update.close();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.CheckForNull;
+
+public interface Select extends SqlStatement<Select> {
+
+ class Row {
+ private final ResultSet rs;
+
+ Row(ResultSet rs) {
+ this.rs = rs;
+ }
+
+ @CheckForNull
+ public Long getNullableLong(int columnIndex) throws SQLException {
+ long l = rs.getLong(columnIndex);
+ return rs.wasNull() ? null : l;
+ }
+
+ public long getLong(int columnIndex) throws SQLException {
+ return rs.getLong(columnIndex);
+ }
+
+ @CheckForNull
+ public Double getNullableDouble(int columnIndex) throws SQLException {
+ double d = rs.getDouble(columnIndex);
+ return rs.wasNull() ? null : d;
+ }
+
+ public double getDouble(int columnIndex) throws SQLException {
+ return rs.getDouble(columnIndex);
+ }
+
+ @CheckForNull
+ public Integer getNullableInt(int columnIndex) throws SQLException {
+ int i = rs.getInt(columnIndex);
+ return rs.wasNull() ? null : i;
+ }
+
+ public int getInt(int columnIndex) throws SQLException {
+ return rs.getInt(columnIndex);
+ }
+
+ @CheckForNull
+ public Boolean getNullableBoolean(int columnIndex) throws SQLException {
+ boolean b = rs.getBoolean(columnIndex);
+ return rs.wasNull() ? null : b;
+ }
+
+ public boolean getBoolean(int columnIndex) throws SQLException {
+ return rs.getBoolean(columnIndex);
+ }
+
+ @CheckForNull
+ public String getNullableString(int columnIndex) throws SQLException {
+ String s = rs.getString(columnIndex);
+ return rs.wasNull() ? null : s;
+ }
+
+ public String getString(int columnIndex) throws SQLException {
+ return rs.getString(columnIndex);
+ }
+
+ @CheckForNull
+ public Date getNullableDate(int columnIndex) throws SQLException {
+ Timestamp t = rs.getTimestamp(columnIndex);
+ return rs.wasNull() ? null : t;
+ }
+
+ public Date getDate(int columnIndex) throws SQLException {
+ return rs.getTimestamp(columnIndex);
+ }
+
+ @CheckForNull
+ public byte[] getNullableBytes(int columnIndex) throws SQLException {
+ byte[] b = rs.getBytes(columnIndex);
+ return rs.wasNull() ? null : b;
+ }
+
+ public byte[] getBytes(int columnIndex) throws SQLException {
+ return rs.getBytes(columnIndex);
+ }
+
+ @Override
+ public String toString() {
+ try {
+ ResultSetMetaData rsMetaData = rs.getMetaData();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i <= rsMetaData.getColumnCount(); i++) {
+ if (i > 1) {
+ sb.append(",");
+ }
+ sb.append(rsMetaData.getColumnLabel(i).toLowerCase());
+ sb.append("=");
+ sb.append(rs.getObject(i));
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ return "Unavailable: " + e.getMessage();
+ }
+ }
+ }
+
+ @FunctionalInterface
+ interface RowReader<T> {
+ T read(Row row) throws SQLException;
+ }
+
+ class LongReader implements RowReader<Long> {
+ private LongReader() {
+ }
+
+ @Override
+ public Long read(Row row) throws SQLException {
+ return row.getNullableLong(1);
+ }
+ }
+
+ RowReader<Long> LONG_READER = new LongReader();
+
+ class StringReader implements RowReader<String> {
+ private StringReader() {
+ }
+
+ @Override
+ public String read(Row row) throws SQLException {
+ return row.getNullableString(1);
+ }
+ }
+
+ RowReader<String> STRING_READER = new StringReader();
+
+ @FunctionalInterface
+ interface RowHandler {
+ void handle(Row row) throws SQLException;
+ }
+
+ <T> List<T> list(RowReader<T> reader) throws SQLException;
+
+ @CheckForNull
+ <T> T get(RowReader<T> reader) throws SQLException;
+
+ void scroll(RowHandler handler) throws SQLException;
+}
--- /dev/null
+/*
+ * 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.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.dbutils.DbUtils;
+import org.sonar.db.Database;
+
+public class SelectImpl extends BaseSqlStatement<Select>implements Select {
+
+ private SelectImpl(PreparedStatement pstmt) {
+ super(pstmt);
+ }
+
+ @Override
+ public <T> List<T> list(Select.RowReader<T> reader) throws SQLException {
+ ResultSet rs = pstmt.executeQuery();
+ Select.Row row = new Select.Row(rs);
+ try {
+ List<T> rows = new ArrayList<>();
+ while (rs.next()) {
+ rows.add(reader.read(row));
+ }
+ return rows;
+ } catch (Exception e) {
+ throw newExceptionWithRowDetails(row, e);
+ } finally {
+ DbUtils.closeQuietly(rs);
+ close();
+ }
+ }
+
+ @Override
+ public <T> T get(Select.RowReader<T> reader) throws SQLException {
+ ResultSet rs = pstmt.executeQuery();
+ Select.Row row = new Select.Row(rs);
+ try {
+ if (rs.next()) {
+ return reader.read(row);
+ }
+ return null;
+ } catch (Exception e) {
+ throw newExceptionWithRowDetails(row, e);
+ } finally {
+ DbUtils.closeQuietly(rs);
+ close();
+ }
+ }
+
+ @Override
+ public void scroll(Select.RowHandler handler) throws SQLException {
+ ResultSet rs = pstmt.executeQuery();
+ Select.Row row = new Select.Row(rs);
+ try {
+ while (rs.next()) {
+ handler.handle(row);
+ }
+ } catch (Exception e) {
+ throw newExceptionWithRowDetails(row, e);
+ } finally {
+ DbUtils.closeQuietly(rs);
+ close();
+ }
+ }
+
+ private static IllegalStateException newExceptionWithRowDetails(Select.Row row, Exception e) {
+ return new IllegalStateException("Error during processing of row: [" + row + "]", e);
+ }
+
+ public static SelectImpl create(Database db, Connection connection, String sql) throws SQLException {
+ // TODO use DbClient#newScrollingSelectStatement()
+ PreparedStatement pstmt = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+ pstmt.setFetchSize(db.getDialect().getScrollDefaultFetchSize());
+ return new SelectImpl(pstmt);
+ }
+}
--- /dev/null
+/*
+ * 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.Date;
+import javax.annotation.Nullable;
+
+public interface SqlStatement<CHILD extends SqlStatement> extends AutoCloseable {
+ CHILD setBoolean(int columnIndex, @Nullable Boolean value) throws SQLException;
+
+ CHILD setDate(int columnIndex, @Nullable Date value) throws SQLException;
+
+ CHILD setDouble(int columnIndex, @Nullable Double value) throws SQLException;
+
+ CHILD setInt(int columnIndex, @Nullable Integer value) throws SQLException;
+
+ CHILD setLong(int columnIndex, @Nullable Long value) throws SQLException;
+
+ CHILD setString(int columnIndex, @Nullable String value) throws SQLException;
+
+ CHILD setBytes(int columnIndex, @Nullable byte[] data) throws SQLException;
+
+ @Override
+ void close();
+}
--- /dev/null
+/*
+ * 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;
+
+/**
+ * INSERT, UPDATE or DELETE
+ */
+public interface Upsert extends SqlStatement<Upsert> {
+ Upsert addBatch() throws SQLException;
+
+ Upsert execute() throws SQLException;
+
+ Upsert commit() throws SQLException;
+}
--- /dev/null
+/*
+ * 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.PreparedStatement;
+import java.sql.SQLException;
+import org.sonar.db.BatchSession;
+
+public class UpsertImpl extends BaseSqlStatement<Upsert> implements Upsert {
+
+ private long batchCount = 0L;
+
+ private UpsertImpl(PreparedStatement pstmt) {
+ super(pstmt);
+ }
+
+ @Override
+ public Upsert addBatch() throws SQLException {
+ pstmt.addBatch();
+ pstmt.clearParameters();
+ batchCount++;
+ if (batchCount % BatchSession.MAX_BATCH_SIZE == 0L) {
+ pstmt.executeBatch();
+ pstmt.getConnection().commit();
+ }
+ return this;
+ }
+
+ @Override
+ public Upsert execute() throws SQLException {
+ if (batchCount == 0L) {
+ pstmt.execute();
+ } else {
+ pstmt.executeBatch();
+ }
+ return this;
+ }
+
+ public long getBatchCount() {
+ return batchCount;
+ }
+
+ @Override
+ public Upsert commit() throws SQLException {
+ pstmt.getConnection().commit();
+ return this;
+ }
+
+ public static UpsertImpl create(Connection connection, String sql) throws SQLException {
+ return new UpsertImpl(connection.prepareStatement(sql));
+ }
+}
import java.sql.SQLException;
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
/**
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanEventsWithoutAnalysisUuid extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanEventsWithoutSnapshotId extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanMeasuresWithNullAnalysisUuid extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanOrphanRowsInProjects extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanOrphanRowsInResourceIndex extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanOrphanRowsInSnapshots extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class CleanUsurperRootComponents extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class DeleteOrphanDuplicationsIndexRowsWithoutComponentOrAnalysis extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class DeleteOrphanMeasuresWithoutComponent extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class DropTreesOfSnapshots extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class FixProjectUuidOfDeveloperProjects extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateAnalysisUuidColumnOnCeActivity extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateAnalysisUuidOnEvents extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateAnalysisUuidOnMeasures extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateComponentUuidAndAnalysisUuidOfDuplicationsIndex extends DataChange {
import java.util.HashMap;
import java.util.Map;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateComponentUuidColumnsOfSnapshots extends DataChange {
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.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateComponentUuidOfMeasures extends DataChange {
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateLastUsedColumnOfRulesProfiles extends DataChange {
import java.util.Map;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
import static org.apache.commons.lang.StringUtils.isBlank;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateUserUpdatedAtOfRulesProfiles extends DataChange {
import java.sql.SQLException;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateUuidColumnOnSnapshots extends DataChange {
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateUuidColumnsOfProjects extends DataChange {
import java.util.HashMap;
import java.util.Map;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateUuidColumnsOfResourceIndex extends DataChange {
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
import static java.util.stream.Collectors.toCollection;
import java.sql.SQLException;
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
import org.sonar.server.platform.db.migration.step.DataChange;
public class RemoveUsersPasswordWhenNotLocal extends DataChange {
import java.util.Date;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
public class CopyActivitiesToQprofileChanges extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
public class DeleteProjectDashboards extends DataChange {
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
public class PopulateTableProperties2 extends DataChange {
private final System2 system2;
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.Upsert;
+import org.sonar.server.platform.db.migration.step.Upsert;
public class RemoveViewsDefinitionFromProperties extends DataChange {
import org.sonar.core.util.UuidFactory;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.Select;
+import org.sonar.server.platform.db.migration.step.Select;
public class CreateDefaultOrganization extends DataChange {
private static final String KEY_DEFAULT_ORGANIZATION = "default-organization";
import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
public class DeletePermissionShareDashboard extends DataChange {
import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
/**
* All users with "admin" role, either directly or via a group, are made root. All others are made non root.
import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
import static com.google.common.base.Preconditions.checkState;
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
import static com.google.common.base.Preconditions.checkState;
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
import static com.google.common.base.Preconditions.checkState;
import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
import static com.google.common.base.Preconditions.checkState;
import org.sonar.api.utils.log.Loggers;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.db.version.Select;
+import org.sonar.server.platform.db.migration.step.Select;
import static java.util.Objects.requireNonNull;
import static org.sonar.core.util.stream.Collectors.uniqueIndex;
import java.sql.SQLException;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
-import org.sonar.db.version.Select;
-import org.sonar.db.version.SqlStatement;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
import org.sonar.server.platform.db.migration.step.DataChange;
public class PopulateUuidColumnOfEvents extends DataChange {
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 org.sonar.server.platform.db.migration.step.Select.Row;
+import org.sonar.server.platform.db.migration.step.Select.RowReader;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import java.sql.SQLException;
import org.sonar.db.Database;
-import org.sonar.db.version.MassUpdate;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
public class DeleteOrphanDuplicationsIndexRowsWithoutComponent extends BaseDataChange {
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.sql.Types;
-import java.util.Date;
-import javax.annotation.Nullable;
-import org.apache.commons.dbutils.DbUtils;
-
-class BaseSqlStatement<CHILD extends SqlStatement> implements SqlStatement<CHILD> {
- protected PreparedStatement pstmt;
-
- protected BaseSqlStatement(PreparedStatement pstmt) {
- this.pstmt = pstmt;
- }
-
- @Override
- public void close() {
- DbUtils.closeQuietly(pstmt);
- pstmt = null;
- }
-
- @Override
- public CHILD setString(int columnIndex, @Nullable String value) throws SQLException {
- pstmt.setString(columnIndex, value);
- return (CHILD) this;
- }
-
- @Override
- public CHILD setBytes(int columnIndex, @Nullable byte[] value) throws SQLException {
- pstmt.setBytes(columnIndex, value);
- return (CHILD) this;
- }
-
- @Override
- public CHILD setInt(int columnIndex, @Nullable Integer value) throws SQLException {
- if (value == null) {
- pstmt.setNull(columnIndex, Types.INTEGER);
- } else {
- pstmt.setInt(columnIndex, value);
- }
- return (CHILD) this;
- }
-
- @Override
- public CHILD setLong(int columnIndex, @Nullable Long value) throws SQLException {
- if (value == null) {
- pstmt.setNull(columnIndex, Types.BIGINT);
- } else {
- pstmt.setLong(columnIndex, value);
- }
- return (CHILD) this;
- }
-
- @Override
- public CHILD setBoolean(int columnIndex, @Nullable Boolean value) throws SQLException {
- if (value == null) {
- pstmt.setNull(columnIndex, Types.BOOLEAN);
- } else {
- pstmt.setBoolean(columnIndex, value);
- }
- return (CHILD) this;
- }
-
- @Override
- public CHILD setDouble(int columnIndex, @Nullable Double value) throws SQLException {
- if (value == null) {
- pstmt.setNull(columnIndex, Types.DECIMAL);
- } else {
- pstmt.setDouble(columnIndex, value);
- }
- return (CHILD) this;
- }
-
- @Override
- public CHILD setDate(int columnIndex, @Nullable Date value) throws SQLException {
- if (value == null) {
- pstmt.setNull(columnIndex, Types.TIMESTAMP);
- } else {
- pstmt.setTimestamp(columnIndex, new Timestamp(value.getTime()));
- }
- return (CHILD) this;
- }
-}
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-import org.sonar.core.util.ProgressLogger;
-import org.sonar.db.Database;
-
-import static com.google.common.base.Preconditions.checkState;
-
-public class MassUpdate {
-
- @FunctionalInterface
- public interface Handler {
- /**
- * Convert some column values of a given row.
- *
- * @return true if the row must be updated, else false. If false, then the update parameter must not be touched.
- */
- boolean handle(Select.Row row, SqlStatement update) throws SQLException;
- }
-
- @FunctionalInterface
- public interface MultiHandler {
- /**
- * Convert some column values of a given row.
- *
- * @param updateIndex 0-based
- * @return true if the row must be updated, else false. If false, then the update parameter must not be touched.
- */
- boolean handle(Select.Row row, SqlStatement update, int updateIndex) throws SQLException;
- }
-
- private final Database db;
- private final Connection readConnection;
- private final Connection writeConnection;
- private final AtomicLong counter = new AtomicLong(0L);
- private final ProgressLogger progress = ProgressLogger.create(getClass(), counter);
-
- private Select select;
- private List<UpsertImpl> updates = new ArrayList<>(1);
-
- public MassUpdate(Database db, Connection readConnection, Connection writeConnection) {
- this.db = db;
- this.readConnection = readConnection;
- this.writeConnection = writeConnection;
- }
-
- public SqlStatement select(String sql) throws SQLException {
- this.select = SelectImpl.create(db, readConnection, sql);
- return this.select;
- }
-
- public MassUpdate update(String sql) throws SQLException {
- this.updates.add(UpsertImpl.create(writeConnection, sql));
- return this;
- }
-
- public MassUpdate rowPluralName(String s) {
- this.progress.setPluralLabel(s);
- return this;
- }
-
- public void execute(Handler handler) throws SQLException {
- checkState(select != null && !updates.isEmpty(), "SELECT or UPDATE requests are not defined");
- checkState(updates.size() == 1, "There should be only one update when using a " + Handler.class.getName());
-
- progress.start();
- try {
- select.scroll(row -> callSingleHandler(handler, updates.iterator().next(), row));
- closeUpdates();
-
- // log the total number of processed rows
- progress.log();
- } finally {
- progress.stop();
- }
- }
-
- public void execute(MultiHandler handler) throws SQLException {
- checkState(select != null && !updates.isEmpty(), "SELECT or UPDATE(s) requests are not defined");
-
- progress.start();
- try {
- select.scroll(row -> callMultiHandler(handler, updates, row));
- closeUpdates();
-
- // log the total number of processed rows
- progress.log();
- } finally {
- progress.stop();
- }
- }
-
- private void callSingleHandler(Handler handler, Upsert update, Select.Row row) throws SQLException {
- if (handler.handle(row, update)) {
- update.addBatch();
- }
- counter.getAndIncrement();
- }
-
- private void callMultiHandler(MultiHandler handler, List<UpsertImpl> updates, Select.Row row) throws SQLException {
- int i = 0;
- for (UpsertImpl update : updates) {
- if (handler.handle(row, update, i)) {
- update.addBatch();
- }
- i++;
- }
- counter.getAndIncrement();
- }
-
- private void closeUpdates() throws SQLException {
- for (UpsertImpl update : updates) {
- if (update.getBatchCount() > 0L) {
- update.execute().commit();
- }
- update.close();
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.util.Date;
-import java.util.List;
-import javax.annotation.CheckForNull;
-
-public interface Select extends SqlStatement<Select> {
-
- class Row {
- private final ResultSet rs;
-
- Row(ResultSet rs) {
- this.rs = rs;
- }
-
- @CheckForNull
- public Long getNullableLong(int columnIndex) throws SQLException {
- long l = rs.getLong(columnIndex);
- return rs.wasNull() ? null : l;
- }
-
- public long getLong(int columnIndex) throws SQLException {
- return rs.getLong(columnIndex);
- }
-
- @CheckForNull
- public Double getNullableDouble(int columnIndex) throws SQLException {
- double d = rs.getDouble(columnIndex);
- return rs.wasNull() ? null : d;
- }
-
- public double getDouble(int columnIndex) throws SQLException {
- return rs.getDouble(columnIndex);
- }
-
- @CheckForNull
- public Integer getNullableInt(int columnIndex) throws SQLException {
- int i = rs.getInt(columnIndex);
- return rs.wasNull() ? null : i;
- }
-
- public int getInt(int columnIndex) throws SQLException {
- return rs.getInt(columnIndex);
- }
-
- @CheckForNull
- public Boolean getNullableBoolean(int columnIndex) throws SQLException {
- boolean b = rs.getBoolean(columnIndex);
- return rs.wasNull() ? null : b;
- }
-
- public boolean getBoolean(int columnIndex) throws SQLException {
- return rs.getBoolean(columnIndex);
- }
-
- @CheckForNull
- public String getNullableString(int columnIndex) throws SQLException {
- String s = rs.getString(columnIndex);
- return rs.wasNull() ? null : s;
- }
-
- public String getString(int columnIndex) throws SQLException {
- return rs.getString(columnIndex);
- }
-
- @CheckForNull
- public Date getNullableDate(int columnIndex) throws SQLException {
- Timestamp t = rs.getTimestamp(columnIndex);
- return rs.wasNull() ? null : t;
- }
-
- public Date getDate(int columnIndex) throws SQLException {
- return rs.getTimestamp(columnIndex);
- }
-
- @CheckForNull
- public byte[] getNullableBytes(int columnIndex) throws SQLException {
- byte[] b = rs.getBytes(columnIndex);
- return rs.wasNull() ? null : b;
- }
-
- public byte[] getBytes(int columnIndex) throws SQLException {
- return rs.getBytes(columnIndex);
- }
-
- @Override
- public String toString() {
- try {
- ResultSetMetaData rsMetaData = rs.getMetaData();
- StringBuilder sb = new StringBuilder();
- for (int i = 1; i <= rsMetaData.getColumnCount(); i++) {
- if (i > 1) {
- sb.append(",");
- }
- sb.append(rsMetaData.getColumnLabel(i).toLowerCase());
- sb.append("=");
- sb.append(rs.getObject(i));
- }
- return sb.toString();
- } catch (Exception e) {
- return "Unavailable: " + e.getMessage();
- }
- }
- }
-
- @FunctionalInterface
- interface RowReader<T> {
- T read(Row row) throws SQLException;
- }
-
- class LongReader implements RowReader<Long> {
- private LongReader() {
- }
-
- @Override
- public Long read(Row row) throws SQLException {
- return row.getNullableLong(1);
- }
- }
-
- RowReader<Long> LONG_READER = new LongReader();
-
- class StringReader implements RowReader<String> {
- private StringReader() {
- }
-
- @Override
- public String read(Row row) throws SQLException {
- return row.getNullableString(1);
- }
- }
-
- RowReader<String> STRING_READER = new StringReader();
-
- @FunctionalInterface
- interface RowHandler {
- void handle(Row row) throws SQLException;
- }
-
- <T> List<T> list(RowReader<T> reader) throws SQLException;
-
- @CheckForNull
- <T> T get(RowReader<T> reader) throws SQLException;
-
- void scroll(RowHandler handler) throws SQLException;
-}
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.dbutils.DbUtils;
-import org.sonar.db.Database;
-
-public class SelectImpl extends BaseSqlStatement<Select>implements Select {
-
- private SelectImpl(PreparedStatement pstmt) {
- super(pstmt);
- }
-
- @Override
- public <T> List<T> list(Select.RowReader<T> reader) throws SQLException {
- ResultSet rs = pstmt.executeQuery();
- Select.Row row = new Select.Row(rs);
- try {
- List<T> rows = new ArrayList<>();
- while (rs.next()) {
- rows.add(reader.read(row));
- }
- return rows;
- } catch (Exception e) {
- throw newExceptionWithRowDetails(row, e);
- } finally {
- DbUtils.closeQuietly(rs);
- close();
- }
- }
-
- @Override
- public <T> T get(Select.RowReader<T> reader) throws SQLException {
- ResultSet rs = pstmt.executeQuery();
- Select.Row row = new Select.Row(rs);
- try {
- if (rs.next()) {
- return reader.read(row);
- }
- return null;
- } catch (Exception e) {
- throw newExceptionWithRowDetails(row, e);
- } finally {
- DbUtils.closeQuietly(rs);
- close();
- }
- }
-
- @Override
- public void scroll(Select.RowHandler handler) throws SQLException {
- ResultSet rs = pstmt.executeQuery();
- Select.Row row = new Select.Row(rs);
- try {
- while (rs.next()) {
- handler.handle(row);
- }
- } catch (Exception e) {
- throw newExceptionWithRowDetails(row, e);
- } finally {
- DbUtils.closeQuietly(rs);
- close();
- }
- }
-
- private static IllegalStateException newExceptionWithRowDetails(Select.Row row, Exception e) {
- return new IllegalStateException("Error during processing of row: [" + row + "]", e);
- }
-
- public static SelectImpl create(Database db, Connection connection, String sql) throws SQLException {
- // TODO use DbClient#newScrollingSelectStatement()
- PreparedStatement pstmt = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- pstmt.setFetchSize(db.getDialect().getScrollDefaultFetchSize());
- return new SelectImpl(pstmt);
- }
-}
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.SQLException;
-import java.util.Date;
-import javax.annotation.Nullable;
-
-public interface SqlStatement<CHILD extends SqlStatement> extends AutoCloseable {
- CHILD setBoolean(int columnIndex, @Nullable Boolean value) throws SQLException;
-
- CHILD setDate(int columnIndex, @Nullable Date value) throws SQLException;
-
- CHILD setDouble(int columnIndex, @Nullable Double value) throws SQLException;
-
- CHILD setInt(int columnIndex, @Nullable Integer value) throws SQLException;
-
- CHILD setLong(int columnIndex, @Nullable Long value) throws SQLException;
-
- CHILD setString(int columnIndex, @Nullable String value) throws SQLException;
-
- CHILD setBytes(int columnIndex, @Nullable byte[] data) throws SQLException;
-
- @Override
- void close();
-}
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.SQLException;
-
-/**
- * INSERT, UPDATE or DELETE
- */
-public interface Upsert extends SqlStatement<Upsert> {
- Upsert addBatch() throws SQLException;
-
- Upsert execute() throws SQLException;
-
- Upsert commit() throws SQLException;
-}
+++ /dev/null
-/*
- * 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.db.version;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import org.sonar.db.BatchSession;
-
-public class UpsertImpl extends BaseSqlStatement<Upsert> implements Upsert {
-
- private long batchCount = 0L;
-
- private UpsertImpl(PreparedStatement pstmt) {
- super(pstmt);
- }
-
- @Override
- public Upsert addBatch() throws SQLException {
- pstmt.addBatch();
- pstmt.clearParameters();
- batchCount++;
- if (batchCount % BatchSession.MAX_BATCH_SIZE == 0L) {
- pstmt.executeBatch();
- pstmt.getConnection().commit();
- }
- return this;
- }
-
- @Override
- public Upsert execute() throws SQLException {
- if (batchCount == 0L) {
- pstmt.execute();
- } else {
- pstmt.executeBatch();
- }
- return this;
- }
-
- public long getBatchCount() {
- return batchCount;
- }
-
- @Override
- public Upsert commit() throws SQLException {
- pstmt.getConnection().commit();
- return this;
- }
-
- public static UpsertImpl create(Connection connection, String sql) throws SQLException {
- return new UpsertImpl(connection.prepareStatement(sql));
- }
-}