2828import com .github .games647 .craftapi .UUIDAdapter ;
2929import com .github .games647 .fastlogin .core .StoredProfile ;
3030import com .github .games647 .fastlogin .core .shared .FastLoginCore ;
31+ import com .github .games647 .fastlogin .core .shared .FloodgateState ;
3132import com .zaxxer .hikari .HikariConfig ;
3233import com .zaxxer .hikari .HikariDataSource ;
3334
3435import java .sql .Connection ;
36+ import java .sql .DatabaseMetaData ;
3537import java .sql .PreparedStatement ;
3638import java .sql .ResultSet ;
3739import java .sql .SQLException ;
@@ -51,13 +53,15 @@ public abstract class SQLStorage implements AuthStorage {
5153 + "`UUID` CHAR(36), "
5254 + "`Name` VARCHAR(16) NOT NULL, "
5355 + "`Premium` BOOLEAN NOT NULL, "
54- + "`Floodgate` BOOLEAN NOT NULL, "
5556 + "`LastIp` VARCHAR(255) NOT NULL, "
5657 + "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
5758 //the premium shouldn't steal the cracked account by changing the name
5859 + "UNIQUE (`Name`) "
5960 + ')' ;
6061
62+ protected static final String ADD_FLOODGATE_COLUMN_STMT = "ALTER TABLE `" + PREMIUM_TABLE
63+ + "` ADD COLUMN `Floodgate` INTEGER(3)" ;
64+
6165 protected static final String LOAD_BY_NAME = "SELECT * FROM `" + PREMIUM_TABLE
6266 + "` WHERE `Name`=? LIMIT 1" ;
6367 protected static final String LOAD_BY_UUID = "SELECT * FROM `" + PREMIUM_TABLE
@@ -88,11 +92,23 @@ public void createTables() throws SQLException {
8892 // choose surrogate PK(ID), because UUID can be null for offline players
8993 // if UUID is always Premium UUID we would have to update offline player entries on insert
9094 // name cannot be PK, because it can be changed for premium players
91-
9295 //todo: add unique uuid index usage
9396 try (Connection con = dataSource .getConnection ();
94- Statement createStmt = con .createStatement ()) {
95- createStmt .executeUpdate (CREATE_TABLE_STMT );
97+ Statement stmt = con .createStatement ()) {
98+ stmt .executeUpdate (getCreateTableStmt ());
99+
100+ // add Floodgate column
101+ DatabaseMetaData md = con .getMetaData ();
102+ if (isColumnMissing (md , "Floodgate" )) {
103+ stmt .executeUpdate (ADD_FLOODGATE_COLUMN_STMT );
104+ }
105+
106+ }
107+ }
108+
109+ private boolean isColumnMissing (DatabaseMetaData metaData , String columnName ) throws SQLException {
110+ try (ResultSet rs = metaData .getColumns (null , null , PREMIUM_TABLE , columnName )) {
111+ return !rs .next ();
96112 }
97113 }
98114
@@ -104,7 +120,8 @@ public StoredProfile loadProfile(String name) {
104120 loadStmt .setString (1 , name );
105121
106122 try (ResultSet resultSet = loadStmt .executeQuery ()) {
107- return parseResult (resultSet ).orElseGet (() -> new StoredProfile (null , name , false , false , "" ));
123+ return parseResult (resultSet ).orElseGet (() -> new StoredProfile (null , name , false ,
124+ FloodgateState .FALSE , "" ));
108125 }
109126 } catch (SQLException sqlEx ) {
110127 core .getPlugin ().getLog ().error ("Failed to query profile: {}" , name , sqlEx );
@@ -137,9 +154,19 @@ private Optional<StoredProfile> parseResult(ResultSet resultSet) throws SQLExcep
137154
138155 String name = resultSet .getString ("Name" );
139156 boolean premium = resultSet .getBoolean ("Premium" );
157+ int floodgateNum = resultSet .getInt ("Floodgate" );
158+ FloodgateState floodgate ;
159+
160+ // if the player wasn't migrated to the new database format
161+ if (resultSet .wasNull ()) {
162+ floodgate = FloodgateState .NOT_MIGRATED ;
163+ } else {
164+ floodgate = FloodgateState .fromInt (floodgateNum );
165+ }
166+
140167 String lastIp = resultSet .getString ("LastIp" );
141168 Instant lastLogin = resultSet .getTimestamp ("LastLogin" ).toInstant ();
142- return Optional .of (new StoredProfile (userId , uuid , name , premium , lastIp , lastLogin ));
169+ return Optional .of (new StoredProfile (userId , uuid , name , premium , floodgate , lastIp , lastLogin ));
143170 }
144171
145172 return Optional .empty ();
@@ -157,9 +184,10 @@ public void save(StoredProfile playerProfile) {
157184 saveStmt .setString (1 , uuid );
158185 saveStmt .setString (2 , playerProfile .getName ());
159186 saveStmt .setBoolean (3 , playerProfile .isPremium ());
160- saveStmt .setString (4 , playerProfile .getLastIp ());
187+ saveStmt .setInt (4 , playerProfile .getFloodgate ().getValue ());
188+ saveStmt .setString (5 , playerProfile .getLastIp ());
161189
162- saveStmt .setLong (5 , playerProfile .getRowId ());
190+ saveStmt .setLong (6 , playerProfile .getRowId ());
163191 saveStmt .execute ();
164192 }
165193 } else {
@@ -168,7 +196,9 @@ public void save(StoredProfile playerProfile) {
168196
169197 saveStmt .setString (2 , playerProfile .getName ());
170198 saveStmt .setBoolean (3 , playerProfile .isPremium ());
171- saveStmt .setString (4 , playerProfile .getLastIp ());
199+ saveStmt .setBoolean (3 , playerProfile .isPremium ());
200+ saveStmt .setInt (4 , playerProfile .getFloodgate ().getValue ());
201+ saveStmt .setString (5 , playerProfile .getLastIp ());
172202
173203 saveStmt .execute ();
174204 try (ResultSet generatedKeys = saveStmt .getGeneratedKeys ()) {
@@ -186,6 +216,14 @@ public void save(StoredProfile playerProfile) {
186216 }
187217 }
188218
219+ /**
220+ * SQLite has a slightly different syntax, so this will be overridden by SQLiteStorage
221+ * @return An SQL Statement to create the `premium` table
222+ */
223+ protected String getCreateTableStmt () {
224+ return CREATE_TABLE_STMT ;
225+ }
226+
189227 @ Override
190228 public void close () {
191229 dataSource .close ();
0 commit comments