/**
* PermissionsEx
* Copyright (C) zml and PermissionsEx contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ninja.leaping.permissionsex.backend.sql;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import ninja.leaping.permissionsex.backend.sql.dao.LegacyDao;
import ninja.leaping.permissionsex.backend.sql.dao.LegacyMigration;
import ninja.leaping.permissionsex.rank.RankLadder;
import ninja.leaping.permissionsex.util.ThrowingSupplier;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
/**
* Abstraction to communicate with the SQL database. Instances are not thread-safe -- it's best to create a new one for each operation on a single thread
*/
public abstract class SqlDao implements AutoCloseable {
private final Connection conn;
private final SqlDataStore ds;
int holdOpen, transactionLevel;
public SqlDao(SqlDataStore ds) throws SQLException {
this.ds = ds;
this.conn = ds.getDataSource().getConnection();
}
// -- Queries
protected String getSelectGlobalParameterQuery() {
return "SELECT (`value`) FROM {}global WHERE `key`=?";
}
protected abstract String getInsertGlobalParameterQueryUpdating();
protected String getDeleteGlobalParameterQuery() {
return "DELETE FROM {}global WHERE `key`=?";
}
protected String getGetSubjectRefIdQuery() {
return "SELECT type, identifier FROM {}subjects WHERE id=?";
}
protected String getGetSubjectRefTypeNameQuery() {
return "SELECT id FROM {}subjects WHERE type=? AND identifier=?";
}
protected String getDeleteSubjectIdQuery() {
return "DELETE FROM {}subjects WHERE id=?";
}
protected String getDeleteSubjectTypeNameQuery() {
return "DELETE FROM {}subjects WHERE type=? AND identifier=?";
}
protected String getInsertSubjectTypeNameQuery() {
return "INSERT INTO {}subjects (type, identifier) VALUES (?, ?)";
}
protected String getSelectContextsSegmentQuery() {
return "SELECT `key`, `value` FROM {}contexts WHERE segment=?";
}
protected String getSelectSegmentsSubjectQuery() {
return "SELECT id, perm_default FROM {}segments WHERE subject=?";
}
protected String getSelectPermissionsSegmentQuery() {
return "SELECT `key`, `value` FROM {}permissions WHERE segment=?";
}
protected String getSelectOptionsSegmentQuery() {
return "SELECT `key`, `value` FROM {}options WHERE segment=?";
}
protected String getSelectInheritanceSegmentQuery() {
return "SELECT * FROM {}inheritance LEFT JOIN ({}subjects) on ({}inheritance.parent={}subjects.id) WHERE segment=?";
}
protected String getInsertSegmentQuery() {
return "INSERT INTO {}segments (subject, perm_default) VALUES (?, ?)";
}
protected String getDeleteSegmentIdQuery() {
return "DELETE FROM {}segments WHERE id=?";
}
protected String getSelectSubjectIdentifiersQuery() {
return "SELECT identifier FROM {}subjects WHERE type=?";
}
protected String getSelectSubjectTypesQuery() {
return "SELECT DISTINCT type FROM {}subjects";
}
protected String getDeleteOptionKeyQuery() {
return "DELETE FROM {}options WHERE segment=? AND `key`=?";
}
protected String getDeleteOptionsQuery() {
return "DELETE FROM {}options WHERE segment=?";
}
protected abstract String getInsertOptionUpdatingQuery();
protected abstract String getInsertPermissionUpdatingQuery();
protected String getDeletePermissionKeyQuery() {
return "DELETE FROM {}permissions WHERE segment=? AND `key`=?";
}
protected String getDeletePermissionsQuery() {
return "DELETE FROM {}permissions WHERE segment=?";
}
protected String getUpdatePermissionDefaultQuery() {
return "UPDATE {}segments SET perm_default=? WHERE id=?";
}
protected String getInsertInheritanceQuery() {
return "INSERT INTO {}inheritance (`segment`, `parent`) VALUES (?, ?)";
}
protected String getDeleteInheritanceParentQuery() {
return "DELETE FROM {}inheritance WHERE segment=? AND parent=?";
}
protected String getDeleteInheritanceQuery() {
return "DELETE FROM {}inheritance WHERE segment=?";
}
protected String getInsertContextQuery() {
return "INSERT INTO {}contexts (segment, `key`, `value`) VALUES (?, ?, ?)";
}
protected String getDeleteContextQuery() {
return "DELETE FROM {}contexts WHERE segment=?";
}
protected String getSelectContextInheritanceQuery() {
return "SELECT `child_key`, `child_value`, `parent_key`, `parent_value` FROM {}context_inheritance ORDER BY `child_key`, `child_value`, `id` ASC";
}
protected String getInsertContextInheritanceQuery() {
return "INSERT INTO {}context_inheritance (child_key, child_value, parent_key, parent_value) VALUES (?, ?, ?, ?)";
}
protected String getDeleteContextInheritanceQuery() {
return "DELETE FROM {}context_inheritance WHERE child_key=? AND child_value=?";
}
protected String getSelectRankLadderQuery() {
return "SELECT `{}rank_ladders`.`id`, `subject`, `type`, `identifier` FROM {}rank_ladders LEFT JOIN (`{}subjects`) ON (`{}rank_ladders`.`subject`=`{}subjects`.`id`) WHERE `name`=? ORDER BY `{}rank_ladders`.`id` ASC";
}
protected String getTestRankLadderExistsQuery() {
return "SELECT `id` FROM {}rank_ladders WHERE `name`=? LIMIT 1";
}
protected String getInsertRankLadderQuery() {
return "INSERT INTO {}rank_ladders (`name`, `subject`) VALUES (?, ?)";
}
protected String getDeleteRankLadderQuery() {
return "DELETE FROM {}rank_ladders WHERE `name`=?";
}
protected String getSelectAllRankLadderNamesQuery() {
return "SELECT DISTINCT `name` FROM {}rank_ladders";
}
protected String getSelectAllSubjectsQuery() {
return "SELECT `id`, `type`, `identifier` FROM {}subjects";
}
public String getRenameTableQuery() {
return "ALTER TABLE ? RENAME ?";
}
public PreparedStatement prepareStatement(String query) throws SQLException {
return conn.prepareStatement(this.ds.insertPrefix(query));
}
protected PreparedStatement prepareStatement(String query, int params) throws SQLException {
return conn.prepareStatement(this.ds.insertPrefix(query), params);
}
protected <T> T executeInTransaction(ThrowingSupplier<T, SQLException> func) throws SQLException {
transactionLevel++;
conn.setAutoCommit(false);
try {
T ret = func.supply();
if (--transactionLevel <= 0) {
conn.commit();
}
return ret;
} finally {
if (transactionLevel <= 0) {
conn.setAutoCommit(true);
}
}
}
// -- Operations
public LegacyDao legacy() {
return LegacyDao.INSTANCE;
}
public Optional<String> getGlobalParameter(String key) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getSelectGlobalParameterQuery())) {
stmt.setString(1, key);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return Optional.of(rs.getString(1));
} else {
return Optional.empty();
}
}
}
public void setGlobalParameter(String key, String value) throws SQLException {
if (value == null) {
try (PreparedStatement stmt = prepareStatement(getDeleteGlobalParameterQuery())) {
stmt.setString(1, key);
stmt.executeUpdate();
}
} else {
try (PreparedStatement stmt = prepareStatement(getInsertGlobalParameterQueryUpdating())) {
stmt.setString(1, key);
stmt.setString(2, value);
stmt.executeUpdate();
}
}
}
public Optional<SubjectRef> getSubjectRef(int id) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getGetSubjectRefIdQuery())) {
stmt.setInt(1, id);
ResultSet res = stmt.executeQuery();
if (!res.next()) {
return Optional.empty();
}
return Optional.of(new SubjectRef(id, res.getString(1), res.getString(2)));
}
}
public Optional<SubjectRef> getSubjectRef(String type, String name) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getGetSubjectRefTypeNameQuery())) {
stmt.setString(1, type);
stmt.setString(2, name);
ResultSet res = stmt.executeQuery();
if (!res.next()) {
return Optional.empty();
}
return Optional.of(new SubjectRef(res.getInt(1), type, name));
}
}
public boolean removeSubject(SubjectRef ref) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getDeleteSubjectIdQuery())) {
stmt.setInt(1, ref.getId());
return stmt.executeUpdate() > 0;
}
}
public boolean removeSubject(String type, String name) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getDeleteSubjectTypeNameQuery())) {
stmt.setString(1, type);
stmt.setString(2, name);
return stmt.executeUpdate() > 0;
}
}
public SubjectRef getOrCreateSubjectRef(String type, String name) throws SQLException {
final SubjectRef ret = SubjectRef.unresolved(type, name);
allocateSubjectRef(ret);
return ret;
}
public void allocateSubjectRef(SubjectRef ref) throws SQLException {
executeInTransaction(() -> {
try (PreparedStatement stmt = prepareStatement(getGetSubjectRefTypeNameQuery())) {
stmt.setString(1, ref.getType());
stmt.setString(2, ref.getIdentifier());
ResultSet res = stmt.executeQuery();
if (res.next()) {
ref.setId(res.getInt(1));
} else {
try (PreparedStatement addStatement = prepareStatement(getInsertSubjectTypeNameQuery(), Statement.RETURN_GENERATED_KEYS)) {
addStatement.setString(1, ref.getType());
addStatement.setString(2, ref.getIdentifier());
addStatement.executeUpdate();
res = addStatement.getGeneratedKeys();
res.next();
ref.setId(res.getInt(1));
}
}
}
return ref;
});
}
public int getIdAllocating(SubjectRef ref) throws SQLException {
if (ref.isUnallocated()) {
allocateSubjectRef(ref);
}
return ref.getId();
}
private Set<Entry<String, String>> getSegmentContexts(int segmentId) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getSelectContextsSegmentQuery())) {
stmt.setInt(1, segmentId);
ImmutableSet.Builder<Entry<String, String>> res = ImmutableSet.builder();
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
res.add(Maps.immutableEntry(rs.getString(1), rs.getString(2)));
}
return res.build();
}
}
public List<Segment> getSegments(SubjectRef ref) throws SQLException {
ImmutableList.Builder<Segment> result = ImmutableList.builder();
try (PreparedStatement stmt = prepareStatement(getSelectSegmentsSubjectQuery())) {
stmt.setInt(1, getIdAllocating(ref));
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
final int id = rs.getInt(1);
Number permDef = (Number) rs.getObject(2);
Set<Entry<String, String>> contexts = getSegmentContexts(id);
ImmutableMap.Builder<String, Integer> permValues = ImmutableMap.builder();
ImmutableMap.Builder<String, String> optionValues = ImmutableMap.builder();
ImmutableList.Builder<SubjectRef> inheritanceValues = ImmutableList.builder();
try (PreparedStatement permStmt = prepareStatement(getSelectPermissionsSegmentQuery())) {
permStmt.setInt(1, id);
ResultSet segmentRs = permStmt.executeQuery();
while (segmentRs.next()) {
permValues.put(segmentRs.getString(1), segmentRs.getInt(2));
}
}
try (PreparedStatement optStmt = prepareStatement(getSelectOptionsSegmentQuery())) {
optStmt.setInt(1, id);
ResultSet segmentRs = optStmt.executeQuery();
while (segmentRs.next()) {
optionValues.put(segmentRs.getString(1), segmentRs.getString(2));
}
}
try (PreparedStatement inheritStmt = prepareStatement(getSelectInheritanceSegmentQuery())) {
inheritStmt.setInt(1, id);
ResultSet segmentRs = inheritStmt.executeQuery();
while (segmentRs.next()) {
inheritanceValues.add(new SubjectRef(segmentRs.getInt(3), segmentRs.getString(4), segmentRs.getString(5)));
}
}
result.add(new Segment(id, contexts, permValues.build(), optionValues.build(), inheritanceValues.build(), permDef == null ? null : permDef.intValue(), null));
}
}
return result.build();
}
public Segment addSegment(SubjectRef ref) throws SQLException { // TODO: Is this method useful?
Segment segment = Segment.unallocated();
allocateSegment(ref, segment);
return segment;
}
public void updateFullSegment(SubjectRef ref, Segment segment) throws SQLException {
executeInTransaction(() -> {
allocateSegment(ref, segment);
setContexts(segment, segment.getContexts());
setOptions(segment, segment.getOptions());
setParents(segment, segment.getParents());
setPermissions(segment, segment.getPermissions());
setDefaultValue(segment, segment.getPermissionDefault());
return null;
});
}
public void setContexts(Segment seg, Set<Entry<String, String>> contexts) throws SQLException {
// Update contexts
executeInTransaction(() -> {
try (PreparedStatement delete = prepareStatement(getDeleteContextQuery());
PreparedStatement insert = prepareStatement(getInsertContextQuery())) {
delete.setInt(1, seg.getId());
delete.executeUpdate();
insert.setInt(1, seg.getId());
for (Map.Entry<String, String> context : contexts) {
insert.setString(2, context.getKey());
insert.setString(3, context.getValue());
insert.addBatch();
}
insert.executeBatch();
}
return null;
});
}
public void allocateSegment(SubjectRef subject, Segment val) throws SQLException {
if (!val.isUnallocated()) {
return;
}
try (PreparedStatement stmt = prepareStatement(getInsertSegmentQuery(), Statement.RETURN_GENERATED_KEYS)) {
stmt.setInt(1, getIdAllocating(subject));
if (val.getPermissionDefault() == null) {
stmt.setNull(2, Types.INTEGER);
} else {
stmt.setInt(2, val.getPermissionDefault());
}
stmt.executeUpdate();
ResultSet res = stmt.getGeneratedKeys();
res.next();
val.setId(res.getInt(1));
}
setContexts(val, val.getContexts());
}
public boolean removeSegment(Segment segment) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getDeleteSegmentIdQuery())) {
stmt.setInt(1, segment.getId());
return stmt.executeUpdate() > 0;
}
}
public Set<String> getAllIdentifiers(String type) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getSelectSubjectIdentifiersQuery())) {
stmt.setString(1, type);
ResultSet rs = stmt.executeQuery();
ImmutableSet.Builder<String> ret = ImmutableSet.builder();
while (rs.next()) {
ret.add(rs.getString(1));
}
return ret.build();
}
}
public Set<String> getRegisteredTypes() throws SQLException {
try (ResultSet rs = prepareStatement(getSelectSubjectTypesQuery()).executeQuery()) {
ImmutableSet.Builder<String> ret = ImmutableSet.builder();
while (rs.next()) {
ret.add(rs.getString(1));
}
return ret.build();
}
}
public void initializeTables() throws SQLException {
if (hasTable("permissions")) {
return;
}
String database = conn.getMetaData().getDatabaseProductName().toLowerCase();
try (InputStream res = SqlDao.class.getResourceAsStream("deploy/" + database + ".sql")) {
if (res == null) {
throw new SQLException("No initial schema available for " + database + " databases!");
}
try (BufferedReader read = new BufferedReader(new InputStreamReader(res, StandardCharsets.UTF_8))) {
executeStream(read);
}
} catch (IOException e) {
throw new SQLException(e);
}
}
void executeStream(BufferedReader reader) throws SQLException, IOException {
try (Statement stmt = conn.createStatement()) {
StringBuilder currentQuery = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("--")) {
continue;
}
currentQuery.append(line);
if (line.endsWith(";")) {
currentQuery.deleteCharAt(currentQuery.length() - 1);
String queryLine = currentQuery.toString().trim();
currentQuery = new StringBuilder();
if (!queryLine.isEmpty()) {
stmt.addBatch(ds.insertPrefix(queryLine));
}
}
}
stmt.executeBatch();
}
}
private boolean hasTable(String table) throws SQLException {
return conn.getMetaData().getTables(null, null, this.ds.getTableName(table).toUpperCase(), null).next(); // Upper-case for H2
}
public void clearOption(Segment segment, String option) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getDeleteOptionKeyQuery())) {
stmt.setInt(1, segment.getId());
stmt.setString(2, option);
stmt.executeUpdate();
}
}
public void setOptions(Segment seg, Map<String, String> options) throws SQLException {
executeInTransaction(() -> {
try (PreparedStatement del = prepareStatement(getDeleteOptionsQuery());
PreparedStatement ins = prepareStatement(getInsertOptionUpdatingQuery())) {
del.setInt(1, seg.getId());
del.executeUpdate();
if (options != null) {
ins.setInt(1, seg.getId());
for (Map.Entry<String, String> ent : options.entrySet()) {
ins.setString(2, ent.getKey());
ins.setString(3, ent.getValue());
ins.addBatch();
}
ins.executeBatch();
}
}
return null;
});
}
public void setOption(Segment segment, String key, String value) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getInsertOptionUpdatingQuery())) {
stmt.setInt(1, segment.getId());
stmt.setString(2, key);
stmt.setString(3, value);
stmt.executeUpdate();
}
}
public void setPermission(Segment segment, String permission, int value) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getInsertPermissionUpdatingQuery())) {
stmt.setInt(1, segment.getId());
stmt.setString(2, permission);
stmt.setInt(3, value);
stmt.executeUpdate();
}
}
public void clearPermission(Segment segment, String permission) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getDeletePermissionKeyQuery())) {
stmt.setInt(1, segment.getId());
stmt.setString(2, permission);
stmt.executeUpdate();
}
}
public void setPermissions(Segment segment, Map<String, Integer> permissions) throws SQLException {
executeInTransaction(() -> {
try (PreparedStatement del = prepareStatement(getDeletePermissionsQuery());
PreparedStatement ins = prepareStatement(getInsertPermissionUpdatingQuery())) {
del.setInt(1, segment.getId());
del.executeUpdate();
if (permissions != null) {
ins.setInt(1, segment.getId());
for (Map.Entry<String, Integer> ent : permissions.entrySet()) {
ins.setString(2, ent.getKey());
ins.setInt(3, ent.getValue());
ins.addBatch();
}
ins.executeBatch();
}
}
return null;
});
}
public void setDefaultValue(Segment segment, Integer permissionDefault) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getUpdatePermissionDefaultQuery())) {
if (permissionDefault == null) {
stmt.setNull(1, Types.INTEGER);
} else {
stmt.setInt(1, permissionDefault);
}
stmt.setInt(2, segment.getId());
stmt.executeUpdate();
}
}
public void addParent(Segment seg, SubjectRef parent) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getInsertInheritanceQuery())) {
stmt.setInt(1, seg.getId());
stmt.setInt(2, getIdAllocating(parent));
stmt.executeUpdate();
}
}
public void removeParent(Segment segment, SubjectRef parent) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getDeleteInheritanceParentQuery())) {
stmt.setInt(1, segment.getId());
stmt.setInt(2, getIdAllocating(parent));
stmt.executeUpdate();
}
}
public void setParents(Segment segment, List<SubjectRef> parents) throws SQLException {
executeInTransaction(() -> {
try (PreparedStatement del = prepareStatement(getDeleteInheritanceQuery());
PreparedStatement ins = prepareStatement(getInsertInheritanceQuery())) {
del.setInt(1, segment.getId());
del.executeUpdate();
if (parents != null) {
ins.setInt(1, segment.getId());
for (SubjectRef ent : parents) {
ins.setInt(2, getIdAllocating(ent));
ins.addBatch();
}
ins.executeBatch();
}
}
return null;
});
}
public SqlContextInheritance getContextInheritance() throws SQLException {
try (PreparedStatement stmt = prepareStatement(getSelectContextInheritanceQuery())) {
ImmutableMap.Builder<Entry<String, String>, List<Entry<String, String>>> ret = ImmutableMap.builder();
Entry<String, String> current = null;
ImmutableList.Builder<Entry<String, String>> builder = null;
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
final String childKey = rs.getString(1),
childValue = rs.getString(2),
parentKey = rs.getString(3),
parentValue = rs.getString(4);
if (current == null || !childKey.equals(current.getKey()) || !childValue.equals(current.getValue())) {
if (current != null && builder != null) {
ret.put(current, builder.build());
}
current = Maps.immutableEntry(childKey, childValue);
builder = ImmutableList.builder();
}
builder.add(Maps.immutableEntry(parentKey, parentValue));
}
if (current != null) {
ret.put(current, builder.build());
}
return new SqlContextInheritance(ret.build(), null);
}
}
public void setContextInheritance(Entry<String, String> child, List<Entry<String, String>> parents) throws SQLException {
executeInTransaction(() -> {
try (PreparedStatement delete = prepareStatement(getDeleteContextInheritanceQuery());
PreparedStatement insert = prepareStatement(getInsertContextInheritanceQuery())) {
delete.setString(1, child.getKey());
delete.setString(2, child.getValue());
delete.executeUpdate();
if (parents != null && parents.size() > 0) {
insert.setString(1, child.getKey());
insert.setString(2, child.getValue());
for (Entry<String, String> parent : parents) {
insert.setString(3, parent.getKey());
insert.setString(4, parent.getValue());
insert.addBatch();
}
insert.executeBatch();
}
}
return null;
});
}
public RankLadder getRankLadder(String name) throws SQLException {
ImmutableList.Builder<SubjectRef> elements = ImmutableList.builder();
try (PreparedStatement stmt = prepareStatement(getSelectRankLadderQuery())) {
stmt.setString(1, name);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
elements.add(new SubjectRef(rs.getInt(2), rs.getString(3), rs.getString(4)));
}
}
return new SqlRankLadder(name, elements.build());
}
public boolean hasEntriesForRankLadder(String name) throws SQLException {
try (PreparedStatement stmt = prepareStatement(getTestRankLadderExistsQuery())) {
stmt.setString(1, name);
return stmt.executeQuery().next();
}
}
public void setRankLadder(String name, RankLadder ladder) throws SQLException {
executeInTransaction(() -> {
List<SubjectRef> ranks;
if (ladder == null) {
ranks = ImmutableList.of();
} else if (ladder instanceof SqlRankLadder) {
ranks = ((SqlRankLadder) ladder).getRanks();
} else {
ranks = Lists.transform(ladder.getRanks(), rank -> rank instanceof SubjectRef ? (SubjectRef) rank : SubjectRef.unresolved(rank.getKey(), rank.getValue()));
}
try (PreparedStatement delete = prepareStatement(getDeleteRankLadderQuery());
PreparedStatement insert = prepareStatement(getInsertRankLadderQuery())) {
delete.setString(1, name);
delete.executeUpdate();
if (ladder != null) {
insert.setString(1, name);
for (SubjectRef ref : ranks) {
insert.setInt(2, getIdAllocating(ref));
insert.addBatch();
}
insert.executeBatch();
}
}
return null;
});
}
public Iterable<String> getAllRankLadderNames() throws SQLException {
try (PreparedStatement stmt = prepareStatement(getSelectAllRankLadderNamesQuery())) {
ImmutableSet.Builder<String> ret = ImmutableSet.builder();
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
ret.add(rs.getString(1));
}
return ret.build();
}
}
public Iterable<SubjectRef> getAllSubjectRefs() throws SQLException {
try (PreparedStatement stmt = prepareStatement(getSelectAllSubjectsQuery())) {
ImmutableSet.Builder<SubjectRef> ret = ImmutableSet.builder();
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
ret.add(new SubjectRef(rs.getInt(1), rs.getString(2), rs.getString(3)));
}
return ret.build();
}
}
@Override
public void close() throws SQLException {
if (this.holdOpen <= 0) {
this.conn.close();
}
}
public void renameTable(String oldName, String newName) throws SQLException {
final String expandedOld = ds.getTableName(oldName);
final String expandedNew = ds.getTableName(newName);
try (PreparedStatement stmt = prepareStatement(getRenameTableQuery())) {
stmt.setString(1, expandedOld);
stmt.setString(2, expandedNew);
stmt.executeUpdate();
}
}
public void deleteTable(String table) throws SQLException {
try (PreparedStatement stmt = prepareStatement("DROP TABLE " + ds.getTableName(table))) {
stmt.executeUpdate();
}
}
/**
* Get the schema version. Has to include backwards compatibility to correctly handle pre-2.x schema updates.
*
* @return The schema version,
* @throws SQLException
*/
public int getSchemaVersion() throws SQLException {
if (hasTable("global")) { // Current
return getGlobalParameter(SqlConstants.OPTION_SCHEMA_VERSION).map(Integer::valueOf).orElse(SqlConstants.VERSION_PRE_VERSIONING);
} else if (legacy().hasTable(this, "permissions")) { // Legacy option
String ret = legacy().getOption(this, "system", LegacyMigration.Type.WORLD, null, "schema-version");
return ret == null ? SqlConstants.VERSION_PRE_VERSIONING : Integer.valueOf(ret);
} else {
return SqlConstants.VERSION_NOT_INITIALIZED;
}
}
public void setSchemaVersion(int version) throws SQLException {
setGlobalParameter(SqlConstants.OPTION_SCHEMA_VERSION, Integer.toString(version));
}
public SqlDataStore getDataStore() {
return ds;
}
public Connection getConnection() {
return conn;
}
}