Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Fix: Improved Schema Version Validation and Error Handling" #158

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This software is released into the Public Domain. See copying.txt for details.
// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.apidb.v0_6.impl;

import java.sql.ResultSet;
Expand Down Expand Up @@ -33,83 +33,84 @@ public class SchemaVersionValidator {

/**
* Creates a new instance.
*
*
* @param credentials Contains all information required to connect to the database.
* @param preferences The database preferences.
*/
public SchemaVersionValidator(DatabaseLoginCredentials credentials, DatabasePreferences preferences) {
this.credentials = credentials;
this.credentials = credentials;
this.preferences = preferences;
}

/**
* Validates that the schema migrations match the expected list of migrations. This method
* caches the result allowing it to be called multiple times without a performance penalty.
*
*
* @param expectedMigrations The expected schema migrations.
*/
public void validateVersion(String[] expectedMigrations) {
if (!validated) {
validateDBVersion(expectedMigrations);

validated = true;
}
}

/**
* Performs the database lookup and validates the expected version.
*
*
* @param expectedMigrations The expected schema migrations.
*/
private void validateDBVersion(String[] expectedMigrations) {
if (preferences.getValidateSchemaVersion()) {
try (DatabaseContext dbCtx = new DatabaseContext(credentials)) {
Set<String> actualMigrationSet;
Set<String> expectedMigrationSet;
List<String> matchingMigrations;
Set<String> actualMigrationSet = new HashSet<>();
Set<String> expectedMigrationSet = new HashSet<>();
List<String> matchingMigrations = new ArrayList<>();

// Load the expected migrations into a Set.
expectedMigrationSet = new HashSet<String>();
// Load expected migrations into a Set
for (String expectedMigration : expectedMigrations) {
expectedMigrationSet.add(expectedMigration);
}

// Load the database migrations into a Set.
actualMigrationSet = new HashSet<String>();
// Load actual migrations from the database into a Set
try (ResultSet resultSet = dbCtx.executeQuery(SELECT_SQL)) {
while (resultSet.next()) {
actualMigrationSet.add(resultSet.getString("version"));
}
while (resultSet.next()) {
actualMigrationSet.add(resultSet.getString("version"));
}
} catch (SQLException e) {
throw new OsmosisRuntimeException("Unable to retrieve existing database migrations", e);
throw new OsmosisRuntimeException("Unable to retrieve existing database migrations", e);
}

// Remove items from both sets that are identical.
matchingMigrations = new ArrayList<String>();
// Find matching migrations
for (String migration : expectedMigrationSet) {
if (actualMigrationSet.contains(migration)) {
matchingMigrations.add(migration);
}
}
// Remove matched migrations from both sets
for (String migration : matchingMigrations) {
expectedMigrationSet.remove(migration);
actualMigrationSet.remove(migration);
}

// If either Set contains elements, we have a schema version mismatch.
if (expectedMigrationSet.size() > 0 || actualMigrationSet.size() > 0) {
StringBuilder errorMessage;

errorMessage = new StringBuilder();

errorMessage.append("Database version mismatch.");
if (expectedMigrationSet.size() > 0) {
errorMessage.append(" The schema is missing migrations " + expectedMigrationSet
+ ", may need to upgrade schema or specify validateSchemaVersion=no.");
// Check for mismatches
if (!expectedMigrationSet.isEmpty() || !actualMigrationSet.isEmpty()) {
StringBuilder errorMessage = new StringBuilder();
errorMessage.append("Database version mismatch detected.\n");

if (!expectedMigrationSet.isEmpty()) {
errorMessage.append("Missing migrations: ").append(expectedMigrationSet).append(".\n")
.append("To resolve:\n")
.append("1. Check your current database version:\n")
.append(" - Run: SELECT * FROM schema_migrations;\n")
.append("2. If outdated, apply the correct schema:\n")
.append(" - Use 'pgsimple_schema_0.6.sql' for version 5.\n")
.append(" - Use 'pgsnapshot_schema_0.6.sql' for version 6.\n");
}
if (actualMigrationSet.size() > 0) {
errorMessage.append(" The schema contains unexpected migrations " + actualMigrationSet
+ ", may need to upgrade osmosis or specify validateSchemaVersion=no.");

if (!actualMigrationSet.isEmpty()) {
errorMessage.append("Unexpected migrations found: ").append(actualMigrationSet).append(".\n")
.append("Consider upgrading Osmosis or set 'validateSchemaVersion=no' if this is intentional.\n");
}

if (preferences.getAllowIncorrectSchemaVersion()) {
Expand Down
Loading