2013-01-25 04:53:02 +01:00
package com.gmail.nossr50.database ;
2012-04-27 11:47:11 +02:00
import java.sql.Connection ;
import java.sql.DriverManager ;
2012-06-05 16:13:10 +02:00
import java.sql.PreparedStatement ;
2012-04-27 11:47:11 +02:00
import java.sql.ResultSet ;
import java.sql.SQLException ;
import java.util.ArrayList ;
2012-06-05 16:13:10 +02:00
import java.util.HashMap ;
2013-01-16 01:03:13 +01:00
import java.util.Map ;
2012-04-27 11:47:11 +02:00
import java.util.Properties ;
2012-06-05 16:13:10 +02:00
2013-01-14 06:47:47 +01:00
2012-06-07 00:02:22 +02:00
import com.gmail.nossr50.mcMMO ;
2012-04-27 11:47:11 +02:00
import com.gmail.nossr50.config.Config ;
2013-03-01 06:52:01 +01:00
import com.gmail.nossr50.datatypes.database.DatabaseUpdateType ;
import com.gmail.nossr50.datatypes.skills.SkillType ;
import com.gmail.nossr50.runnables.database.SQLReconnectTask ;
2013-03-12 21:25:42 +01:00
import com.gmail.nossr50.util.Misc ;
2013-03-01 06:52:01 +01:00
public final class DatabaseManager {
2012-12-28 11:40:15 +01:00
private static String connectionString ;
2012-07-10 18:04:18 +02:00
2013-01-26 23:01:55 +01:00
private static String tablePrefix = Config . getInstance ( ) . getMySQLTablePrefix ( ) ;
2012-07-10 18:04:18 +02:00
private static Connection connection = null ;
2012-10-22 14:45:16 +02:00
// Scale waiting time by this much per failed attempt
2013-01-11 03:41:35 +01:00
private static final double SCALING_FACTOR = 40 ;
2012-12-24 22:56:25 +01:00
2012-10-22 14:45:16 +02:00
// Minimum wait in nanoseconds (default 500ms)
2013-03-01 06:52:01 +01:00
private static final long MIN_WAIT = 500L * 1000000L ;
2012-10-22 14:45:16 +02:00
// Maximum time to wait between reconnects (default 5 minutes)
2012-12-28 11:40:15 +01:00
private static final long MAX_WAIT = 5L * 60L * 1000L * 1000000L ;
2012-10-22 14:45:16 +02:00
// How long to wait when checking if connection is valid (default 3 seconds)
private static final int VALID_TIMEOUT = 3 ;
// When next to try connecting to Database in nanoseconds
private static long nextReconnectTimestamp = 0L ;
2012-12-24 22:56:25 +01:00
2013-03-01 06:52:01 +01:00
// How many connection attempts have failed
2012-10-22 14:45:16 +02:00
private static int reconnectAttempt = 0 ;
2012-04-27 11:47:11 +02:00
2013-03-01 06:52:01 +01:00
private static final long ONE_MONTH = 2630000000L ;
private DatabaseManager ( ) { }
2013-01-27 00:28:03 +01:00
2012-04-27 11:47:11 +02:00
/ * *
* Attempt to connect to the mySQL database .
* /
public static void connect ( ) {
2013-01-26 23:01:55 +01:00
Config configInstance = Config . getInstance ( ) ;
2013-01-16 01:03:13 +01:00
connectionString = " jdbc:mysql:// " + configInstance . getMySQLServerName ( ) + " : " + configInstance . getMySQLServerPort ( ) + " / " + configInstance . getMySQLDatabaseName ( ) ;
2013-01-26 23:01:55 +01:00
2013-01-16 01:03:13 +01:00
try {
mcMMO . p . getLogger ( ) . info ( " Attempting connection to MySQL... " ) ;
// Force driver to load if not yet loaded
Class . forName ( " com.mysql.jdbc.Driver " ) ;
Properties connectionProperties = new Properties ( ) ;
connectionProperties . put ( " user " , configInstance . getMySQLUserName ( ) ) ;
connectionProperties . put ( " password " , configInstance . getMySQLUserPassword ( ) ) ;
connectionProperties . put ( " autoReconnect " , " false " ) ;
connectionProperties . put ( " maxReconnects " , " 0 " ) ;
connection = DriverManager . getConnection ( connectionString , connectionProperties ) ;
mcMMO . p . getLogger ( ) . info ( " Connection to MySQL was a success! " ) ;
2013-03-01 06:52:01 +01:00
}
catch ( SQLException ex ) {
2013-01-16 01:03:13 +01:00
connection = null ;
2013-03-01 06:52:01 +01:00
2013-01-27 00:02:01 +01:00
if ( reconnectAttempt = = 0 | | reconnectAttempt > = 11 ) {
mcMMO . p . getLogger ( ) . info ( " Connection to MySQL failed! " ) ;
}
2013-03-01 06:52:01 +01:00
}
catch ( ClassNotFoundException ex ) {
2013-01-16 01:03:13 +01:00
connection = null ;
2013-03-01 06:52:01 +01:00
2013-01-27 00:02:01 +01:00
if ( reconnectAttempt = = 0 | | reconnectAttempt > = 11 ) {
mcMMO . p . getLogger ( ) . info ( " MySQL database driver not found! " ) ;
}
2013-01-16 01:03:13 +01:00
}
2012-04-27 11:47:11 +02:00
}
/ * *
* Attempt to create the database structure .
* /
2013-01-26 23:01:55 +01:00
public static void createStructure ( ) {
2013-01-11 21:26:42 +01:00
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " users` ( "
+ " `id` int(10) unsigned NOT NULL AUTO_INCREMENT, "
2012-04-27 11:47:11 +02:00
+ " `user` varchar(40) NOT NULL, "
+ " `lastlogin` int(32) unsigned NOT NULL, "
+ " PRIMARY KEY (`id`), "
+ " UNIQUE KEY `user` (`user`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; " ) ;
2013-01-11 21:26:42 +01:00
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " huds` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
+ " `hudtype` varchar(50) NOT NULL DEFAULT 'STANDARD', "
2013-01-12 07:43:40 +01:00
+ " PRIMARY KEY (`user_id`), "
2013-01-12 07:23:16 +01:00
+ " FOREIGN KEY (`user_id`) REFERENCES ` " + tablePrefix + " users` (`id`) "
2013-01-11 21:26:42 +01:00
+ " ON DELETE CASCADE) ENGINE=MyISAM DEFAULT CHARSET=latin1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " cooldowns` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
2012-04-27 11:47:11 +02:00
+ " `taming` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `mining` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `woodcutting` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `repair` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `unarmed` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `herbalism` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `excavation` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `archery` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `swords` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `axes` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `acrobatics` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `blast_mining` int(32) unsigned NOT NULL DEFAULT '0', "
2013-01-12 07:43:40 +01:00
+ " PRIMARY KEY (`user_id`), "
2013-01-12 07:23:16 +01:00
+ " FOREIGN KEY (`user_id`) REFERENCES ` " + tablePrefix + " users` (`id`) "
2013-01-11 21:26:42 +01:00
+ " ON DELETE CASCADE) ENGINE=MyISAM DEFAULT CHARSET=latin1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " skills` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
2012-04-27 11:47:11 +02:00
+ " `taming` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `mining` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `woodcutting` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `repair` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `unarmed` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `herbalism` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `excavation` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `archery` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `swords` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `axes` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `acrobatics` int(10) unsigned NOT NULL DEFAULT '0', "
2013-01-12 07:43:40 +01:00
+ " PRIMARY KEY (`user_id`), "
2013-01-12 07:23:16 +01:00
+ " FOREIGN KEY (`user_id`) REFERENCES ` " + tablePrefix + " users` (`id`) "
2013-01-11 21:26:42 +01:00
+ " ON DELETE CASCADE) ENGINE=MyISAM DEFAULT CHARSET=latin1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " experience` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
2012-04-27 11:47:11 +02:00
+ " `taming` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `mining` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `woodcutting` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `repair` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `unarmed` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `herbalism` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `excavation` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `archery` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `swords` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `axes` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `acrobatics` int(10) unsigned NOT NULL DEFAULT '0', "
2013-01-12 07:43:40 +01:00
+ " PRIMARY KEY (`user_id`), "
2013-01-12 07:23:16 +01:00
+ " FOREIGN KEY (`user_id`) REFERENCES ` " + tablePrefix + " users` (`id`) "
2013-01-11 21:26:42 +01:00
+ " ON DELETE CASCADE) ENGINE=MyISAM DEFAULT CHARSET=latin1; " ) ;
2012-04-27 11:47:11 +02:00
2013-03-01 06:52:01 +01:00
checkDatabaseStructure ( DatabaseUpdateType . FISHING ) ;
checkDatabaseStructure ( DatabaseUpdateType . BLAST_MINING ) ;
checkDatabaseStructure ( DatabaseUpdateType . CASCADE_DELETE ) ;
checkDatabaseStructure ( DatabaseUpdateType . INDEX ) ;
2012-04-27 11:47:11 +02:00
}
/ * *
2013-03-01 06:52:01 +01:00
* Attempt to write the SQL query .
2012-04-27 11:47:11 +02:00
*
2013-03-01 06:52:01 +01:00
* @param sql Query to write .
* @return true if the query was successfully written , false otherwise .
2012-04-27 11:47:11 +02:00
* /
2013-03-01 06:52:01 +01:00
public static boolean write ( String sql ) {
if ( ! checkConnected ( ) ) {
return false ;
2012-04-27 11:47:11 +02:00
}
2012-10-22 15:03:31 +02:00
PreparedStatement statement = null ;
2012-04-27 11:47:11 +02:00
try {
2012-10-22 15:03:31 +02:00
statement = connection . prepareStatement ( sql ) ;
2013-03-01 06:52:01 +01:00
statement . executeUpdate ( ) ;
return true ;
2012-04-27 11:47:11 +02:00
}
catch ( SQLException ex ) {
2013-03-01 06:52:01 +01:00
printErrors ( ex ) ;
return false ;
}
finally {
2012-12-24 22:56:25 +01:00
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
2013-03-01 06:52:01 +01:00
catch ( SQLException e ) {
printErrors ( e ) ;
return false ;
2012-12-24 22:56:25 +01:00
}
2012-04-27 11:47:11 +02:00
}
}
}
2013-01-16 04:08:59 +01:00
/ * *
* Returns the number of rows affected by either a DELETE or UPDATE query
*
* @param sql SQL query to execute
* @return the number of rows affected
* /
2013-01-26 23:01:55 +01:00
public static int update ( String sql ) {
2013-01-16 04:08:59 +01:00
int ret = 0 ;
2013-03-01 06:52:01 +01:00
2013-01-16 04:08:59 +01:00
if ( checkConnected ( ) ) {
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( sql ) ;
ret = statement . executeUpdate ( ) ;
2013-03-01 06:52:01 +01:00
}
catch ( SQLException ex ) {
2013-01-16 04:08:59 +01:00
printErrors ( ex ) ;
2013-03-01 06:52:01 +01:00
}
finally {
2013-01-16 04:08:59 +01:00
if ( statement ! = null ) {
try {
statement . close ( ) ;
2013-03-01 06:52:01 +01:00
}
catch ( SQLException e ) {
2013-01-16 04:08:59 +01:00
printErrors ( e ) ;
}
}
}
}
return ret ;
}
2012-04-27 11:47:11 +02:00
/ * *
* Get the Integer . Only return first row / first field .
*
* @param sql SQL query to execute
* @return the value in the first row / first field
* /
2013-01-26 23:01:55 +01:00
public static int getInt ( String sql ) {
2013-03-01 06:52:01 +01:00
ResultSet resultSet = null ;
2012-07-10 18:04:18 +02:00
int result = 0 ;
2012-04-27 11:47:11 +02:00
2012-10-22 14:45:16 +02:00
if ( checkConnected ( ) ) {
2013-03-01 06:52:01 +01:00
PreparedStatement statement = null ;
2012-04-27 11:47:11 +02:00
try {
2013-03-01 06:52:01 +01:00
statement = connection . prepareStatement ( sql ) ;
2012-07-10 18:04:18 +02:00
resultSet = statement . executeQuery ( ) ;
if ( resultSet . next ( ) ) {
result = resultSet . getInt ( 1 ) ;
2012-06-28 05:35:56 +02:00
}
else {
result = 0 ;
2012-04-27 11:47:11 +02:00
}
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
2013-03-01 06:52:01 +01:00
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
printErrors ( e ) ;
}
}
}
2012-04-27 11:47:11 +02:00
}
2012-07-10 18:04:18 +02:00
2012-04-27 11:47:11 +02:00
return result ;
}
2012-06-05 15:57:10 +02:00
2012-04-27 11:47:11 +02:00
/ * *
2012-10-22 14:45:16 +02:00
* Check connection status and re - establish if dead or stale .
*
2012-12-24 22:56:25 +01:00
* If the very first immediate attempt fails , further attempts
* will be made in progressively larger intervals up to MAX_WAIT
* intervals .
2012-10-22 14:45:16 +02:00
*
2012-12-24 22:56:25 +01:00
* This allows for MySQL to time out idle connections as needed by
* server operator , without affecting McMMO , while still providing
* protection against a database outage taking down Bukkit ' s tick
2012-10-22 14:45:16 +02:00
* processing loop due to attemping a database connection each
* time McMMO needs the database .
2012-06-05 15:57:10 +02:00
*
2012-04-27 11:47:11 +02:00
* @return the boolean value for whether or not we are connected
* /
2012-10-22 14:45:16 +02:00
public static boolean checkConnected ( ) {
2012-12-24 22:56:25 +01:00
boolean isClosed = true ;
boolean isValid = false ;
boolean exists = ( connection ! = null ) ;
// If we're waiting for server to recover then leave early
if ( nextReconnectTimestamp > 0 & & nextReconnectTimestamp > System . nanoTime ( ) ) {
return false ;
}
if ( exists ) {
2012-10-22 14:45:16 +02:00
try {
2012-12-24 22:56:25 +01:00
isClosed = connection . isClosed ( ) ;
2013-03-01 06:52:01 +01:00
}
catch ( SQLException e ) {
2012-12-24 22:56:25 +01:00
isClosed = true ;
e . printStackTrace ( ) ;
printErrors ( e ) ;
}
2012-10-22 14:45:16 +02:00
if ( ! isClosed ) {
try {
2012-12-24 22:56:25 +01:00
isValid = connection . isValid ( VALID_TIMEOUT ) ;
2013-03-01 06:52:01 +01:00
}
catch ( SQLException e ) {
// Don't print stack trace because it's valid to lose idle connections to the server and have to restart them.
2012-12-24 22:56:25 +01:00
isValid = false ;
}
}
}
// Leave if all ok
if ( exists & & ! isClosed & & isValid ) {
// Housekeeping
nextReconnectTimestamp = 0 ;
reconnectAttempt = 0 ;
return true ;
}
// Cleanup after ourselves for GC and MySQL's sake
if ( exists & & ! isClosed ) {
try {
connection . close ( ) ;
2013-03-01 06:52:01 +01:00
}
catch ( SQLException ex ) {
2012-12-24 22:56:25 +01:00
// This is a housekeeping exercise, ignore errors
2012-10-22 14:45:16 +02:00
}
2012-12-24 22:56:25 +01:00
}
// Try to connect again
connect ( ) ;
// Leave if connection is good
try {
if ( connection ! = null & & ! connection . isClosed ( ) ) {
// Schedule a database save if we really had an outage
if ( reconnectAttempt > 1 ) {
2013-03-01 06:52:01 +01:00
mcMMO . p . getServer ( ) . getScheduler ( ) . scheduleSyncDelayedTask ( mcMMO . p , new SQLReconnectTask ( ) , 5 ) ;
2012-12-24 22:56:25 +01:00
}
nextReconnectTimestamp = 0 ;
reconnectAttempt = 0 ;
return true ;
}
2013-03-01 06:52:01 +01:00
}
catch ( SQLException e ) {
2012-12-24 22:56:25 +01:00
// Failed to check isClosed, so presume connection is bad and attempt later
e . printStackTrace ( ) ;
printErrors ( e ) ;
}
reconnectAttempt + + ;
2013-03-01 06:52:01 +01:00
nextReconnectTimestamp = ( long ) ( System . nanoTime ( ) + Math . min ( MAX_WAIT , ( reconnectAttempt * SCALING_FACTOR * MIN_WAIT ) ) ) ;
2012-12-24 22:56:25 +01:00
return false ;
2012-04-27 11:47:11 +02:00
}
/ * *
* Read SQL query .
*
* @param sql SQL query to read
* @return the rows in this SQL query
* /
2013-01-26 23:01:55 +01:00
public static HashMap < Integer , ArrayList < String > > read ( String sql ) {
2012-07-10 18:04:18 +02:00
ResultSet resultSet ;
HashMap < Integer , ArrayList < String > > rows = new HashMap < Integer , ArrayList < String > > ( ) ;
2012-04-27 11:47:11 +02:00
2012-10-22 14:45:16 +02:00
if ( checkConnected ( ) ) {
2013-03-01 06:52:01 +01:00
PreparedStatement statement = null ;
2012-04-27 11:47:11 +02:00
try {
2013-03-01 06:52:01 +01:00
statement = connection . prepareStatement ( sql ) ;
2012-07-10 18:04:18 +02:00
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
ArrayList < String > column = new ArrayList < String > ( ) ;
for ( int i = 1 ; i < = resultSet . getMetaData ( ) . getColumnCount ( ) ; i + + ) {
column . add ( resultSet . getString ( i ) ) ;
2012-04-27 11:47:11 +02:00
}
2012-07-10 18:04:18 +02:00
rows . put ( resultSet . getRow ( ) , column ) ;
2012-04-27 11:47:11 +02:00
}
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
2013-03-01 06:52:01 +01:00
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
printErrors ( e ) ;
}
}
}
2012-04-27 11:47:11 +02:00
}
2012-07-10 18:04:18 +02:00
return rows ;
2012-04-27 11:47:11 +02:00
}
2013-01-21 23:22:54 +01:00
2013-01-26 23:01:55 +01:00
public static Map < String , Integer > readSQLRank ( String playerName ) {
2013-01-16 01:03:13 +01:00
ResultSet resultSet ;
Map < String , Integer > skills = new HashMap < String , Integer > ( ) ;
2013-02-04 16:33:34 +01:00
2013-01-16 01:03:13 +01:00
if ( checkConnected ( ) ) {
try {
2013-03-01 06:52:01 +01:00
for ( SkillType skillType : SkillType . values ( ) ) {
2013-02-04 16:33:34 +01:00
if ( skillType . isChildSkill ( ) ) {
continue ;
2013-01-16 08:50:18 +01:00
}
2013-02-04 16:33:34 +01:00
2013-03-01 06:52:01 +01:00
String skillName = skillType . name ( ) . toLowerCase ( ) ;
String sql = " SELECT COUNT(*) AS rank FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE " + skillName + " > 0 " +
" AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
" WHERE user = ' " + playerName + " ') " ;
2013-02-04 16:33:34 +01:00
2013-01-16 08:50:18 +01:00
PreparedStatement statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
2013-02-04 16:33:34 +01:00
2013-01-18 00:11:28 +01:00
resultSet . next ( ) ;
2013-02-04 16:33:34 +01:00
2013-01-18 00:11:28 +01:00
int rank = resultSet . getInt ( " rank " ) ;
2013-02-04 16:33:34 +01:00
2013-03-01 06:52:01 +01:00
sql = " SELECT user, " + skillName + " FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE " + skillName + " > 0 " +
" AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
" WHERE user = ' " + playerName + " ') ORDER BY user " ;
2013-02-04 16:33:34 +01:00
2013-01-18 00:11:28 +01:00
statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
2013-02-04 16:33:34 +01:00
2013-01-16 08:50:18 +01:00
while ( resultSet . next ( ) ) {
2013-01-30 18:22:14 +01:00
if ( resultSet . getString ( " user " ) . equalsIgnoreCase ( playerName ) ) {
2013-01-18 00:11:28 +01:00
skills . put ( skillType . name ( ) , rank + resultSet . getRow ( ) ) ;
2013-01-16 19:28:14 +01:00
break ;
}
2013-01-16 01:03:13 +01:00
}
2013-02-04 16:33:34 +01:00
2013-01-16 08:50:18 +01:00
statement . close ( ) ;
2013-01-16 01:03:13 +01:00
}
2013-02-04 17:22:39 +01:00
2013-03-01 06:52:01 +01:00
String sql = " SELECT COUNT(*) AS rank FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
" WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing > 0 " +
" AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing > " +
" (SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing " +
" FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE user = ' " + playerName + " ') " ;
2013-02-04 17:22:39 +01:00
PreparedStatement statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
resultSet . next ( ) ;
int rank = resultSet . getInt ( " rank " ) ;
2013-03-01 06:52:01 +01:00
sql = " SELECT user, taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing " +
" FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
" WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing > 0 " +
" AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing = " +
" (SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing " +
" FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE user = ' " + playerName + " ') ORDER BY user " ;
2013-02-04 17:22:39 +01:00
statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
if ( resultSet . getString ( " user " ) . equalsIgnoreCase ( playerName ) ) {
skills . put ( " ALL " , rank + resultSet . getRow ( ) ) ;
break ;
}
}
statement . close ( ) ;
2013-01-16 01:03:13 +01:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
}
2013-02-04 16:33:34 +01:00
2013-01-16 01:03:13 +01:00
return skills ;
}
2012-04-27 11:47:11 +02:00
2013-01-26 23:01:55 +01:00
public static void purgePowerlessSQL ( ) {
2013-01-27 00:28:03 +01:00
mcMMO . p . getLogger ( ) . info ( " Purging powerless users... " ) ;
2013-03-01 06:52:01 +01:00
HashMap < Integer , ArrayList < String > > usernames ;
usernames = read ( " SELECT u.user FROM " + tablePrefix + " skills AS s, " + tablePrefix + " users AS u " + " WHERE s.user_id = u.id AND " +
" (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0 " ) ;
write ( " DELETE FROM " + tablePrefix + " users WHERE " + tablePrefix + " users.id IN (SELECT * FROM " +
" (SELECT u.id FROM " + tablePrefix + " skills AS s, " + tablePrefix + " users AS u " + " WHERE s.user_id = u.id " +
" AND (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0) AS p) " ) ;
2013-01-14 06:47:47 +01:00
int purgedUsers = 0 ;
for ( int i = 1 ; i < = usernames . size ( ) ; i + + ) {
String playerName = usernames . get ( i ) . get ( 0 ) ;
2013-03-01 06:52:01 +01:00
if ( playerName = = null | | mcMMO . p . getServer ( ) . getOfflinePlayer ( playerName ) . isOnline ( ) ) {
2013-01-14 06:47:47 +01:00
continue ;
}
2013-03-12 21:25:42 +01:00
Misc . profileCleanup ( playerName ) ;
2013-01-14 06:47:47 +01:00
purgedUsers + + ;
}
2013-01-27 00:28:03 +01:00
mcMMO . p . getLogger ( ) . info ( " Purged " + purgedUsers + " users from the database. " ) ;
2013-01-14 06:47:47 +01:00
}
2013-01-26 23:01:55 +01:00
public static void purgeOldSQL ( ) {
2013-01-27 00:28:03 +01:00
mcMMO . p . getLogger ( ) . info ( " Purging old users... " ) ;
2013-01-14 06:47:47 +01:00
long currentTime = System . currentTimeMillis ( ) ;
2013-03-01 06:52:01 +01:00
long purgeTime = ONE_MONTH * Config . getInstance ( ) . getOldUsersCutoff ( ) ;
2013-01-14 06:47:47 +01:00
HashMap < Integer , ArrayList < String > > usernames = read ( " SELECT user FROM " + tablePrefix + " users WHERE (( " + currentTime + " - lastlogin*1000) > " + purgeTime + " ) " ) ;
write ( " DELETE FROM " + tablePrefix + " users WHERE " + tablePrefix + " users.id IN (SELECT * FROM (SELECT id FROM " + tablePrefix + " users WHERE (( " + currentTime + " - lastlogin*1000) > " + purgeTime + " )) AS p) " ) ;
int purgedUsers = 0 ;
for ( int i = 1 ; i < = usernames . size ( ) ; i + + ) {
String playerName = usernames . get ( i ) . get ( 0 ) ;
if ( playerName = = null ) {
continue ;
}
2013-03-12 21:25:42 +01:00
Misc . profileCleanup ( playerName ) ;
2013-01-14 06:47:47 +01:00
purgedUsers + + ;
}
2013-01-27 00:28:03 +01:00
mcMMO . p . getLogger ( ) . info ( " Purged " + purgedUsers + " users from the database. " ) ;
2013-01-14 06:47:47 +01:00
}
2013-03-01 06:52:01 +01:00
/ * *
* Check database structure for missing values .
*
* @param update Type of data to check updates for
* /
private static void checkDatabaseStructure ( DatabaseUpdateType update ) {
String sql = null ;
ResultSet resultSet = null ;
HashMap < Integer , ArrayList < String > > rows = new HashMap < Integer , ArrayList < String > > ( ) ;
switch ( update ) {
case BLAST_MINING :
sql = " SELECT * FROM ` " + tablePrefix + " cooldowns` ORDER BY ` " + tablePrefix + " cooldowns`.`blast_mining` ASC LIMIT 0 , 30 " ;
break ;
case CASCADE_DELETE :
write ( " ALTER TABLE ` " + tablePrefix + " huds` ADD FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE; " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " experience` ADD FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE; " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " cooldowns` ADD FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE; " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " skills` ADD FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE; " ) ;
break ;
case FISHING :
sql = " SELECT * FROM ` " + tablePrefix + " experience` ORDER BY ` " + tablePrefix + " experience`.`fishing` ASC LIMIT 0 , 30 " ;
break ;
case INDEX :
if ( read ( " SHOW INDEX FROM " + tablePrefix + " skills " ) . size ( ) ! = 13 & & checkConnected ( ) ) {
mcMMO . p . getLogger ( ) . info ( " Indexing tables, this may take a while on larger databases " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " skills` ADD INDEX `idx_taming` (`taming`) USING BTREE, "
+ " ADD INDEX `idx_mining` (`mining`) USING BTREE, "
+ " ADD INDEX `idx_woodcutting` (`woodcutting`) USING BTREE, "
+ " ADD INDEX `idx_repair` (`repair`) USING BTREE, "
+ " ADD INDEX `idx_unarmed` (`unarmed`) USING BTREE, "
+ " ADD INDEX `idx_herbalism` (`herbalism`) USING BTREE, "
+ " ADD INDEX `idx_excavation` (`excavation`) USING BTREE, "
+ " ADD INDEX `idx_archery` (`archery`) USING BTREE, "
+ " ADD INDEX `idx_swords` (`swords`) USING BTREE, "
+ " ADD INDEX `idx_axes` (`axes`) USING BTREE, "
+ " ADD INDEX `idx_acrobatics` (`acrobatics`) USING BTREE, "
+ " ADD INDEX `idx_fishing` (`fishing`) USING BTREE; " ) ;
2013-01-14 06:47:47 +01:00
}
2013-03-01 06:52:01 +01:00
break ;
default :
break ;
}
PreparedStatement statement = null ;
try {
if ( ! checkConnected ( ) ) {
return ;
}
statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
ArrayList < String > column = new ArrayList < String > ( ) ;
for ( int i = 1 ; i < = resultSet . getMetaData ( ) . getColumnCount ( ) ; i + + ) {
column . add ( resultSet . getString ( i ) ) ;
}
rows . put ( resultSet . getRow ( ) , column ) ;
2013-01-14 06:47:47 +01:00
}
}
2013-03-01 06:52:01 +01:00
catch ( SQLException ex ) {
switch ( update ) {
case BLAST_MINING :
mcMMO . p . getLogger ( ) . info ( " Updating mcMMO MySQL tables for Blast Mining... " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0' ; " ) ;
break ;
case FISHING :
mcMMO . p . getLogger ( ) . info ( " Updating mcMMO MySQL tables for Fishing... " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " skills` ADD `fishing` int(10) NOT NULL DEFAULT '0' ; " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " experience` ADD `fishing` int(10) NOT NULL DEFAULT '0' ; " ) ;
break ;
default :
break ;
}
}
finally {
if ( resultSet ! = null ) {
try {
resultSet . close ( ) ;
}
catch ( SQLException e ) {
// Ignore the error, we're leaving
}
}
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore the error, we're leaving
}
}
}
}
private static void printErrors ( SQLException ex ) {
mcMMO . p . getLogger ( ) . severe ( " SQLException: " + ex . getMessage ( ) ) ;
mcMMO . p . getLogger ( ) . severe ( " SQLState: " + ex . getSQLState ( ) ) ;
mcMMO . p . getLogger ( ) . severe ( " VendorError: " + ex . getErrorCode ( ) ) ;
2013-01-14 06:47:47 +01:00
}
2013-01-16 01:03:13 +01:00
}