Refactored Patch#hasColumn with Queries

This commit is contained in:
Rsl1122 2019-01-19 22:44:34 +02:00
parent 1080c6de70
commit 26325967ee
5 changed files with 107 additions and 81 deletions

View File

@ -0,0 +1,44 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan 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 Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.db.access;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* SQL query of a COUNT statement that closes proper elements.
*
* @author Rsl1122
*/
public abstract class CountQueryStatement extends QueryStatement<Boolean> {
private String countColumnName = "c";
public CountQueryStatement(String sql) {
super(sql);
}
public CountQueryStatement(String sql, String countColumnName) {
super(sql);
this.countColumnName = countColumnName;
}
@Override
public Boolean processResults(ResultSet set) throws SQLException {
return set.next() && set.getInt(countColumnName) > 0;
}
}

View File

@ -19,19 +19,13 @@ package com.djrapitops.plan.db.patches;
import com.djrapitops.plan.api.exceptions.database.DBOpException; import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.db.DBType; import com.djrapitops.plan.db.DBType;
import com.djrapitops.plan.db.SQLDB; import com.djrapitops.plan.db.SQLDB;
import com.djrapitops.plan.db.access.QueryAllStatement;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.access.transactions.Transaction; import com.djrapitops.plan.db.access.transactions.Transaction;
import com.djrapitops.plan.db.sql.parsing.TableSqlParser; import com.djrapitops.plan.db.sql.parsing.TableSqlParser;
import com.djrapitops.plan.db.sql.queries.H2SchemaQueries; import com.djrapitops.plan.db.sql.queries.H2SchemaQueries;
import com.djrapitops.plan.db.sql.queries.MySQLSchemaQueries; import com.djrapitops.plan.db.sql.queries.MySQLSchemaQueries;
import com.djrapitops.plan.db.sql.queries.SQLiteSchemaQueries; import com.djrapitops.plan.db.sql.queries.SQLiteSchemaQueries;
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
import com.djrapitops.plugin.utilities.Verify; import com.djrapitops.plugin.utilities.Verify;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -79,51 +73,22 @@ public abstract class Patch extends Transaction {
case SQLITE: case SQLITE:
return query(SQLiteSchemaQueries.doesTableExist(tableName)); return query(SQLiteSchemaQueries.doesTableExist(tableName));
case MYSQL: case MYSQL:
return query(MySQLSchemaQueries.doesTableExist(db.getConfig().get(DatabaseSettings.MYSQL_DATABASE), tableName)); return query(MySQLSchemaQueries.doesTableExist(tableName));
default: default:
throw new IllegalStateException("Unsupported Database Type: " + dbType.getName()); throw new IllegalStateException("Unsupported Database Type: " + dbType.getName());
} }
} }
protected boolean hasColumn(String tableName, String columnName) { protected boolean hasColumn(String tableName, String columnName) {
if (dbType.supportsMySQLQueries()) { switch (dbType) {
String query; case H2:
return query(H2SchemaQueries.doesColumnExist(tableName, columnName));
if (dbType == DBType.H2) { case MYSQL:
query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS" + return query(MySQLSchemaQueries.doesColumnExist(tableName, columnName));
" WHERE TABLE_NAME=? AND COLUMN_NAME=?"; case SQLITE:
} else { return query(SQLiteSchemaQueries.doesColumnExist(tableName, columnName));
query = "SELECT * FROM information_schema.COLUMNS" + default:
" WHERE TABLE_NAME=? AND COLUMN_NAME=? AND TABLE_SCHEMA=?"; throw new IllegalStateException("Unsupported Database Type: " + dbType.getName());
}
return query(new QueryStatement<Boolean>(query) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName);
statement.setString(2, columnName);
if (dbType != DBType.H2) {
statement.setString(3, db.getConfig().get(DatabaseSettings.MYSQL_DATABASE));
}
}
@Override
public Boolean processResults(ResultSet set) throws SQLException {
return set.next();
}
});
} else {
return query(new QueryAllStatement<Boolean>("PRAGMA table_info(" + tableName + ")") {
@Override
public Boolean processResults(ResultSet set) throws SQLException {
while (set.next()) {
if (columnName.equals(set.getString("name"))) {
return true;
}
}
return false;
}
});
} }
} }
@ -157,8 +122,7 @@ public abstract class Patch extends Transaction {
return; return;
} }
String schema = db.getConfig().get(DatabaseSettings.MYSQL_DATABASE); List<MySQLSchemaQueries.ForeignKeyConstraint> constraints = query(MySQLSchemaQueries.foreignKeyConstraintsOf(referencedTable));
List<MySQLSchemaQueries.ForeignKeyConstraint> constraints = query(MySQLSchemaQueries.foreignKeyConstraintsOf(schema, referencedTable));
for (MySQLSchemaQueries.ForeignKeyConstraint constraint : constraints) { for (MySQLSchemaQueries.ForeignKeyConstraint constraint : constraints) {
// Uses information from https://stackoverflow.com/a/34574758 // Uses information from https://stackoverflow.com/a/34574758
@ -172,8 +136,7 @@ public abstract class Patch extends Transaction {
return; return;
} }
String schema = db.getConfig().get(DatabaseSettings.MYSQL_DATABASE); List<MySQLSchemaQueries.ForeignKeyConstraint> constraints = query(MySQLSchemaQueries.foreignKeyConstraintsOf(table));
List<MySQLSchemaQueries.ForeignKeyConstraint> constraints = query(MySQLSchemaQueries.foreignKeyConstraintsOf(schema, table));
Verify.isTrue(constraints.isEmpty(), () -> new DBOpException("Table '" + table + "' has constraints '" + constraints + "'")); Verify.isTrue(constraints.isEmpty(), () -> new DBOpException("Table '" + table + "' has constraints '" + constraints + "'"));
} }

View File

@ -16,10 +16,10 @@
*/ */
package com.djrapitops.plan.db.sql.queries; package com.djrapitops.plan.db.sql.queries;
import com.djrapitops.plan.db.access.QueryStatement; import com.djrapitops.plan.db.access.CountQueryStatement;
import com.djrapitops.plan.db.access.Query;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
@ -33,17 +33,24 @@ public class H2SchemaQueries {
/* Static method class */ /* Static method class */
} }
public static QueryStatement<Boolean> doesTableExist(String tableName) { public static Query<Boolean> doesTableExist(String tableName) {
String sql = "SELECT COUNT(1) as c FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?"; String sql = "SELECT COUNT(1) as c FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?";
return new QueryStatement<Boolean>(sql) { return new CountQueryStatement(sql) {
@Override @Override
public void prepare(PreparedStatement statement) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName); statement.setString(1, tableName);
} }
};
}
public static Query<Boolean> doesColumnExist(String tableName, String columnName) {
String sql = "SELECT COUNT(1) as c FROM INFORMATION_SCHEMA.COLUMNS" +
" WHERE TABLE_NAME=? AND COLUMN_NAME=?";
return new CountQueryStatement(sql) {
@Override @Override
public Boolean processResults(ResultSet set) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
return set.next() && set.getInt("c") > 0; statement.setString(1, tableName);
statement.setString(2, columnName);
} }
}; };
} }

View File

@ -16,6 +16,8 @@
*/ */
package com.djrapitops.plan.db.sql.queries; package com.djrapitops.plan.db.sql.queries;
import com.djrapitops.plan.db.access.CountQueryStatement;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryStatement; import com.djrapitops.plan.db.access.QueryStatement;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -35,31 +37,24 @@ public class MySQLSchemaQueries {
/* Static method class */ /* Static method class */
} }
public static QueryStatement<Boolean> doesTableExist(String tableSchema, String tableName) { public static Query<Boolean> doesTableExist(String tableName) {
String sql = "SELECT COUNT(1) as c FROM information_schema.TABLES WHERE table_name=? AND TABLE_SCHEMA=?"; String sql = "SELECT COUNT(1) as c FROM information_schema.TABLES WHERE table_name=? AND TABLE_SCHEMA=DATABASE()";
return new QueryStatement<Boolean>(sql) { return new CountQueryStatement(sql) {
@Override @Override
public void prepare(PreparedStatement statement) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName); statement.setString(1, tableName);
statement.setString(2, tableSchema);
}
@Override
public Boolean processResults(ResultSet set) throws SQLException {
return set.next() && set.getInt("c") > 0;
} }
}; };
} }
public static QueryStatement<List<ForeignKeyConstraint>> foreignKeyConstraintsOf(String tableSchema, String referencedTable) { public static Query<List<ForeignKeyConstraint>> foreignKeyConstraintsOf(String referencedTable) {
String keySQL = "SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE" + String keySQL = "SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE" +
" WHERE REFERENCED_TABLE_SCHEMA = ?" + " WHERE REFERENCED_TABLE_SCHEMA = DATABASE()" +
" AND REFERENCED_TABLE_NAME = ?"; " AND REFERENCED_TABLE_NAME = ?";
return new QueryStatement<List<ForeignKeyConstraint>>(keySQL) { return new QueryStatement<List<ForeignKeyConstraint>>(keySQL) {
@Override @Override
public void prepare(PreparedStatement statement) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableSchema); statement.setString(1, referencedTable);
statement.setString(2, referencedTable);
} }
@Override @Override
@ -85,19 +80,26 @@ public class MySQLSchemaQueries {
}; };
} }
public static QueryStatement<Boolean> doesIndexExist(String indexName, String tableName) { public static Query<Boolean> doesIndexExist(String indexName, String tableName) {
String sql = "SELECT COUNT(1) as IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS " + String sql = "SELECT COUNT(1) as c FROM INFORMATION_SCHEMA.STATISTICS " +
"WHERE table_schema=DATABASE() AND table_name=? AND index_name=?"; "WHERE table_schema=DATABASE() AND table_name=? AND index_name=?";
return new QueryStatement<Boolean>(sql) { return new CountQueryStatement(sql) {
@Override @Override
public void prepare(PreparedStatement statement) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName); statement.setString(1, tableName);
statement.setString(2, indexName); statement.setString(2, indexName);
} }
};
}
public static Query<Boolean> doesColumnExist(String tableName, String columnName) {
String sql = "SELECT COUNT(1) as c FROM information_schema.COLUMNS" +
" WHERE TABLE_NAME=? AND COLUMN_NAME=? AND TABLE_SCHEMA=DATABASE()";
return new CountQueryStatement(sql) {
@Override @Override
public Boolean processResults(ResultSet set) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
return set.next() && set.getInt("IndexIsThere") > 0; statement.setString(1, tableName);
statement.setString(2, columnName);
} }
}; };
} }

View File

@ -16,7 +16,9 @@
*/ */
package com.djrapitops.plan.db.sql.queries; package com.djrapitops.plan.db.sql.queries;
import com.djrapitops.plan.db.access.QueryStatement; import com.djrapitops.plan.db.access.CountQueryStatement;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryAllStatement;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -33,19 +35,27 @@ public class SQLiteSchemaQueries {
/* Static method class */ /* Static method class */
} }
public static QueryStatement<Boolean> doesTableExist(String tableName) { public static Query<Boolean> doesTableExist(String tableName) {
String sql = "SELECT COUNT(1) as c FROM sqlite_master WHERE tbl_name=?"; String sql = "SELECT COUNT(1) as c FROM sqlite_master WHERE tbl_name=?";
return new QueryStatement<Boolean>(sql) { return new CountQueryStatement(sql) {
@Override @Override
public void prepare(PreparedStatement statement) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName); statement.setString(1, tableName);
} }
@Override
public Boolean processResults(ResultSet set) throws SQLException {
return set.next() && set.getInt("c") > 0;
}
}; };
} }
public static Query<Boolean> doesColumnExist(String tableName, String columnName) {
return new QueryAllStatement<Boolean>("PRAGMA table_info(" + tableName + ")") {
@Override
public Boolean processResults(ResultSet set) throws SQLException {
while (set.next()) {
if (columnName.equals(set.getString("name"))) {
return true;
}
}
return false;
}
};
}
} }