datenbank

This commit is contained in:
BlubbFish 2016-01-26 08:20:14 +00:00
parent 1c8d49f9d9
commit 6513a92c77
6 changed files with 6203 additions and 0 deletions

View File

@ -0,0 +1,527 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SQLite;
using MySql;
using MySql.Data.Common;
using MySql.Data.MySqlClient;
namespace BF2Statistics.Database
{
public class DatabaseDriver : IDisposable
{
/// <summary>
/// Current DB Engine
/// </summary>
public DatabaseEngine DatabaseEngine { get; protected set; }
/// <summary>
/// The database connection
/// </summary>
public DbConnection Connection { get; protected set; }
/// <summary>
/// Returns whether the Database connection is open
/// </summary>
public bool IsConnected
{
get { return (Connection.State == ConnectionState.Open); }
}
/// <summary>
/// Returns the current conenction state of the database
/// </summary>
public ConnectionState State
{
get { return Connection.State; }
}
/// <summary>
/// Gets the number of queries ran by this instance
/// </summary>
public int NumQueries = 0;
/// <summary>
/// Random, yes... But its used here when building queries dynamically
/// </summary>
protected static char Comma = ',';
/// <summary>
/// Indicates whether the disposed method was called
/// </summary>
protected bool IsDisposed = false;
/// <summary>
/// Constructor
/// </summary>
/// <param name="Engine">The string name, for the GetDatabaseEngine() method</param>
/// <param name="Host">The Database server IP Address</param>
/// <param name="Port">The Database server Port Number</param>
/// <param name="DatabaseName">The name of the database</param>
/// <param name="User">A username, with database privliages</param>
/// <param name="Pass">The password to the User</param>
public DatabaseDriver(string Engine, string Host, int Port, string DatabaseName, string User, string Pass)
{
// Set class variables, and create a new connection builder
this.DatabaseEngine = GetDatabaseEngine(Engine);
DbConnectionStringBuilder Builder;
// Establish the connection
if (this.DatabaseEngine == DatabaseEngine.Sqlite)
{
// Create the connection
Builder = new SQLiteConnectionStringBuilder();
Builder.Add("Data Source", Path.Combine(Program.RootPath, DatabaseName + ".sqlite3"));
Connection = new SQLiteConnection(Builder.ConnectionString);
}
else if (this.DatabaseEngine == DatabaseEngine.Mysql)
{
// Create the connection
Builder = new MySqlConnectionStringBuilder();
Builder.Add("Server", Host);
Builder.Add("Port", Port);
Builder.Add("User ID", User);
Builder.Add("Password", Pass);
Builder.Add("Database", DatabaseName);
Builder.Add("Convert Zero Datetime", "true");
Connection = new MySqlConnection(Builder.ConnectionString);
}
else
{
throw new Exception("Invalid Database type.");
}
}
/// <summary>
/// Destructor
/// </summary>
~DatabaseDriver()
{
Dispose();
}
/// <summary>
/// Disposes the DB connection
/// </summary>
public void Dispose()
{
if(Connection != null && !IsDisposed)
{
try
{
Connection.Close();
Connection.Dispose();
}
catch (ObjectDisposedException) { }
IsDisposed = true;
}
}
/// <summary>
/// Opens the database connection
/// </summary>
public void Connect()
{
if (Connection.State != ConnectionState.Open)
{
try
{
Connection.Open();
}
catch (Exception e)
{
throw new DbConnectException("Unable to etablish database connection", e);
}
}
}
/// <summary>
/// Closes the connection to the database
/// </summary>
public void Close()
{
try {
if (Connection.State != ConnectionState.Closed)
Connection.Close();
}
catch (ObjectDisposedException) { }
}
/// <summary>
/// Creates a new command to be executed on the database
/// </summary>
/// <param name="QueryString"></param>
public DbCommand CreateCommand(string QueryString)
{
if (DatabaseEngine == Database.DatabaseEngine.Sqlite)
return new SQLiteCommand(QueryString, Connection as SQLiteConnection);
else
return new MySqlCommand(QueryString, Connection as MySqlConnection);
}
/// <summary>
/// Creates a DbParameter using the current Database engine's Parameter object
/// </summary>
/// <returns></returns>
public DbParameter CreateParam()
{
if (DatabaseEngine == Database.DatabaseEngine.Sqlite)
return (new SQLiteParameter() as DbParameter);
else
return (new MySqlParameter() as DbParameter);
}
/// <summary>
/// Queries the database, and returns a result set
/// </summary>
/// <param name="Sql">The SQL Statement to run on the database</param>
/// <returns></returns>
public List<Dictionary<string, object>> Query(string Sql)
{
return this.Query(Sql, new List<DbParameter>());
}
/// <summary>
/// Queries the database, and returns a result set
/// </summary>
/// <param name="Sql">The SQL Statement to run on the database</param>
/// <param name="Items">Additional parameters are parameter values for the query.
/// The first parameter replaces @P0, second @P1 etc etc.
/// </param>
/// <returns></returns>
public List<Dictionary<string, object>> Query(string Sql, params object[] Items)
{
List<DbParameter> Params = new List<DbParameter>(Items.Length);
for (int i = 0; i < Items.Length; i++)
{
DbParameter Param = this.CreateParam();
Param.ParameterName = "@P" + i;
Param.Value = Items[i];
Params.Add(Param);
}
return this.Query(Sql, Params);
}
/// <summary>
/// Queries the database, and returns a result set
/// </summary>
/// <param name="Sql">The SQL Statement to run on the database</param>
/// <param name="Params">A list of sql params to add to the command</param>
/// <returns></returns>
public List<Dictionary<string, object>> Query(string Sql, List<DbParameter> Params)
{
// Create our Rows result
List<Dictionary<string, object>> Rows = new List<Dictionary<string, object>>();
// Increase Query Count
NumQueries++;
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
{
// Add params
foreach (DbParameter Param in Params)
Command.Parameters.Add(Param);
// Execute the query
using (DbDataReader Reader = Command.ExecuteReader())
{
// If we have rows, add them to the list
if (Reader.HasRows)
{
// Add each row to the rows list
while (Reader.Read())
{
Dictionary<string, object> Row = new Dictionary<string, object>(Reader.FieldCount);
for (int i = 0; i < Reader.FieldCount; ++i)
Row.Add(Reader.GetName(i), Reader.GetValue(i));
Rows.Add(Row);
}
}
// Cleanup
Reader.Close();
}
}
// Return Rows
return Rows;
}
/// <summary>
/// Queries the database, and returns 1 row at a time until all rows are returned
/// </summary>
/// <param name="Sql">The SQL Statement to run on the database</param>
/// <returns></returns>
public IEnumerable<Dictionary<string, object>> QueryReader(string Sql)
{
// Increase Query Count
NumQueries++;
// Create the SQL Command, and execute the reader
using (DbCommand Command = this.CreateCommand(Sql))
using (DbDataReader Reader = Command.ExecuteReader())
{
// If we have rows, add them to the list
if (Reader.HasRows)
{
// Add each row to the rows list
while (Reader.Read())
{
Dictionary<string, object> Row = new Dictionary<string, object>(Reader.FieldCount);
for (int i = 0; i < Reader.FieldCount; ++i)
Row.Add(Reader.GetName(i), Reader.GetValue(i));
yield return Row;
}
}
// Cleanup
Reader.Close();
}
}
/// <summary>
/// Executes a command, and returns 1 row at a time until all rows are returned
/// </summary>
/// <param name="Command">The database command to execute the reader on</param>
/// <returns></returns>
public IEnumerable<Dictionary<string, object>> QueryReader(DbCommand Command)
{
// Increase Query Count
NumQueries++;
// Execute the query
using (Command)
using (DbDataReader Reader = Command.ExecuteReader())
{
// If we have rows, add them to the list
if (Reader.HasRows)
{
// Add each row to the rows list
while (Reader.Read())
{
Dictionary<string, object> Row = new Dictionary<string, object>(Reader.FieldCount);
for (int i = 0; i < Reader.FieldCount; ++i)
Row.Add(Reader.GetName(i), Reader.GetValue(i));
yield return Row;
}
}
// Cleanup
Reader.Close();
}
}
/// <summary>
/// Executes a command, and returns the resulting rows
/// </summary>
/// <param name="Command">The database command to execute the reader on</param>
/// <returns></returns>
public List<Dictionary<string, object>> ExecuteReader(DbCommand Command)
{
// Execute the query
List<Dictionary<string, object>> Rows = new List<Dictionary<string, object>>();
// Increase Query Count
NumQueries++;
using (Command)
using (DbDataReader Reader = Command.ExecuteReader())
{
// If we have rows, add them to the list
if (Reader.HasRows)
{
// Add each row to the rows list
while (Reader.Read())
{
Dictionary<string, object> Row = new Dictionary<string, object>(Reader.FieldCount);
for (int i = 0; i < Reader.FieldCount; ++i)
Row.Add(Reader.GetName(i), Reader.GetValue(i));
Rows.Add(Row);
}
}
// Cleanup
Reader.Close();
}
// Return Rows
return Rows;
}
/// <summary>
/// Executes a statement on the database (Update, Delete, Insert)
/// </summary>
/// <param name="Sql">The SQL statement to be executes</param>
/// <returns>Returns the number of rows affected by the statement</returns>
public int Execute(string Sql)
{
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
return Command.ExecuteNonQuery();
}
/// <summary>
/// Executes a statement on the database (Update, Delete, Insert)
/// </summary>
/// <param name="Sql">The SQL statement to be executed</param>
/// <param name="Params">A list of Sqlparameters</param>
/// <returns>Returns the number of rows affected by the statement</returns>
public int Execute(string Sql, List<DbParameter> Params)
{
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
{
// Increase Query Count
NumQueries++;
// Add params
foreach (DbParameter Param in Params)
Command.Parameters.Add(Param);
// Execute command, and dispose of the command
return Command.ExecuteNonQuery();
}
}
/// <summary>
/// Executes a statement on the database (Update, Delete, Insert)
/// </summary>
/// <param name="Sql">The SQL statement to be executed</param>
/// <param name="Items">Additional parameters are parameter values for the query.
/// The first parameter replaces @P0, second @P1 etc etc.
/// </param>
/// <returns>Returns the number of rows affected by the statement</returns>
public int Execute(string Sql, params object[] Items)
{
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
{
// Add params
for (int i = 0; i < Items.Length; i++)
{
DbParameter Param = this.CreateParam();
Param.ParameterName = "@P" + i;
Param.Value = Items[i];
Command.Parameters.Add(Param);
}
// Increase Query Count
NumQueries++;
// Execute command, and dispose of the command
return Command.ExecuteNonQuery();
}
}
/// <summary>
/// Executes the query, and returns the first column of the first row in the result
/// set returned by the query. Additional columns or rows are ignored.
/// </summary>
/// <param name="Sql">The SQL statement to be executed</param>
/// <returns></returns>
public object ExecuteScalar(string Sql)
{
// Increase Query Count
NumQueries++;
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
return Command.ExecuteScalar();
}
/// <summary>
/// Executes the query, and returns the first column of the first row in the result
/// set returned by the query. Additional columns or rows are ignored.
/// </summary>
/// <param name="Sql">The SQL statement to be executed</param>
/// <param name="Params">A list of Sqlparameters</param>
/// <returns></returns>
public object ExecuteScalar(string Sql, List<DbParameter> Params)
{
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
{
// Increase Query Count
NumQueries++;
// Add params
foreach (DbParameter Param in Params)
Command.Parameters.Add(Param);
// Execute command, and dispose of the command
return Command.ExecuteScalar();
}
}
/// <summary>
/// Executes the query, and returns the first column of the first row in the result
/// set returned by the query. Additional columns or rows are ignored.
/// </summary>
/// <param name="Sql">The SQL statement to be executed</param>
/// <param name="Items"></param>
/// <returns></returns>
public object ExecuteScalar(string Sql, params object[] Items)
{
// Create the SQL Command
using (DbCommand Command = this.CreateCommand(Sql))
{
// Add params
for (int i = 0; i < Items.Length; i++)
{
DbParameter Param = this.CreateParam();
Param.ParameterName = "@P" + i;
Param.Value = Items[i];
Command.Parameters.Add(Param);
}
// Increase Query Count
NumQueries++;
// Execute command, and dispose of the command
return Command.ExecuteScalar();
}
}
/// <summary>
/// Begins a new database transaction
/// </summary>
/// <returns></returns>
public DbTransaction BeginTransaction()
{
return Connection.BeginTransaction();
}
/// <summary>
/// Begins a new database transaction
/// </summary>
/// <param name="Level"></param>
/// <returns></returns>
public DbTransaction BeginTransaction(IsolationLevel Level)
{
return Connection.BeginTransaction(Level);
}
/// <summary>
/// Converts a database string name to a DatabaseEngine type.
/// </summary>
/// <param name="Name"></param>
/// <returns></returns>
public static DatabaseEngine GetDatabaseEngine(string Name)
{
return ((DatabaseEngine)Enum.Parse(typeof(DatabaseEngine), Name, true));
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BF2Statistics.Database
{
public enum DatabaseEngine
{
Sqlite,
Mysql,
}
}

View File

@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BF2Statistics.Database
{
/// <summary>
/// A class to provide common tasks against the Gamespy Login Database
/// </summary>
public class GamespyDatabase : DatabaseDriver, IDisposable
{
/// <summary>
/// Constructor
/// </summary>
public GamespyDatabase() :
base(
MainForm.Config.GamespyDBEngine,
MainForm.Config.GamespyDBHost,
MainForm.Config.GamespyDBPort,
MainForm.Config.GamespyDBName,
MainForm.Config.GamespyDBUser,
MainForm.Config.GamespyDBPass
)
{
// Try and Reconnect
try
{
Connect();
// Try to get the database version
try
{
if (base.Query("SELECT dbver FROM _version LIMIT 1").Count == 0)
throw new Exception();
}
catch
{
// If an exception is thrown, table doesnt exist... fresh install
if (DatabaseEngine == DatabaseEngine.Sqlite)
base.Execute(Utils.GetResourceAsString("BF2Statistics.SQL.SQLite.Gamespy.sql"));
else
base.Execute(Utils.GetResourceAsString("BF2Statistics.SQL.MySQL.Gamespy.sql"));
}
}
catch (Exception)
{
if (Connection != null)
Connection.Dispose();
throw;
}
}
/// <summary>
/// Destructor
/// </summary>
~GamespyDatabase()
{
if (!IsDisposed)
base.Dispose();
}
/// <summary>
/// Fetches an account from the gamespy database
/// </summary>
/// <param name="Nick">The user's Nick</param>
/// <returns></returns>
public Dictionary<string, object> GetUser(string Nick)
{
// Fetch the user
var Rows = base.Query("SELECT * FROM accounts WHERE name=@P0", Nick);
return (Rows.Count == 0) ? null : Rows[0];
}
/// <summary>
/// Fetches an account from the gamespy database
/// </summary>
/// <param name="Pid">The account player ID</param>
/// <returns></returns>
public Dictionary<string, object> GetUser(int Pid)
{
// Fetch the user
var Rows = base.Query("SELECT * FROM accounts WHERE id=@P0", Pid);
return (Rows.Count == 0) ? null : Rows[0];
}
/// <summary>
/// Fetches an account from the gamespy database
/// </summary>
/// <param name="Email">Account email</param>
/// <param name="Password">Account Password</param>
/// <returns></returns>
public Dictionary<string, object> GetUser(string Email, string Password)
{
var Rows = base.Query("SELECT * FROM accounts WHERE email=@P0 AND password=@P1", Email, Password);
return (Rows.Count == 0) ? null : Rows[0];
}
/// <summary>
/// Returns a list of player names that are similar to the passed parameter
/// </summary>
/// <param name="Nick"></param>
/// <returns></returns>
public List<string> GetUsersLike(string Nick)
{
// Generate our return list
List<string> List = new List<string>();
var Rows = base.Query("SELECT name FROM accounts WHERE name LIKE @P0", "%" + Nick + "%");
foreach (Dictionary<string, object> Account in Rows)
List.Add(Account["name"].ToString());
return List;
}
/// <summary>
/// Returns wether an account exists from the provided Nick
/// </summary>
/// <param name="Nick"></param>
/// <returns></returns>
public bool UserExists(string Nick)
{
// Fetch the user
return (base.Query("SELECT id FROM accounts WHERE name=@P0", Nick).Count != 0);
}
/// <summary>
/// Returns wether an account exists from the provided Account Id
/// </summary>
/// <param name="PID"></param>
/// <returns></returns>
public bool UserExists(int PID)
{
// Fetch the user
return (base.Query("SELECT name FROM accounts WHERE id=@P0", PID).Count != 0);
}
/// <summary>
/// Creates a new Gamespy Account
/// </summary>
/// <remarks>Used by the login server when a create account request is made</remarks>
/// <param name="Nick">The Account Name</param>
/// <param name="Pass">The Account Password</param>
/// <param name="Email">The Account Email Address</param>
/// <param name="Country">The Country Code for this Account</param>
/// <returns>A bool indicating whether the account was created sucessfully</returns>
public bool CreateUser(string Nick, string Pass, string Email, string Country)
{
int Pid = 0;
// Attempt to connect to stats database, and get a PID from there
/*try
{
// try see if the player ID exists in the stats database
using (StatsDatabase Db = new StatsDatabase())
{
// NOTE: online account names in the stats DB start with a single space!
var Row = Db.Query("SELECT id FROM player WHERE upper(name) = upper(@P0)", " " + Nick);
Pid = (Row.Count == 0) ? GenerateAccountId() : Int32.Parse(Row[0]["id"].ToString());
}
}
catch
{*/
Pid = GenerateAccountId();
//}
// Create the user in the database
int Rows = base.Execute("INSERT INTO accounts(id, name, password, email, country) VALUES(@P0, @P1, @P2, @P3, @P4)",
Pid, Nick, Pass, Email, Country
);
return (Rows != 0);
}
/// <summary>
/// Generates a new Account Id
/// </summary>
/// <returns></returns>
private int GenerateAccountId()
{
var Row = base.Query("SELECT COALESCE(MAX(id), 500000000) AS max FROM accounts");
int max = Int32.Parse(Row[0]["max"].ToString()) + 1;
return (max < 500000000) ? 500000000 : max;
}
/// <summary>
/// Creates a new Gamespy Account
/// </summary>
/// <remarks>Only used in the Gamespy Account Creation Form</remarks>
/// <param name="Pid">The Profile Id to assign this account</param>
/// <param name="Nick">The Account Name</param>
/// <param name="Pass">The Account Password</param>
/// <param name="Email">The Account Email Address</param>
/// <param name="Country">The Country Code for this Account</param>
/// <returns>A bool indicating whether the account was created sucessfully</returns>
public bool CreateUser(int Pid, string Nick, string Pass, string Email, string Country)
{
// Make sure the user doesnt exist!
if (UserExists(Pid))
throw new Exception("Account ID is already taken!");
else if(UserExists(Nick))
throw new Exception("Account username is already taken!");
// Create the user in the database
int Rows = base.Execute("INSERT INTO accounts(id, name, password, email, country) VALUES(@P0, @P1, @P2, @P3, @P4)",
Pid, Nick, Pass, Email, Country
);
return (Rows != 0);
}
/// <summary>
/// Updates an Accounts Country Code
/// </summary>
/// <param name="Nick"></param>
/// <param name="Country"></param>
public void UpdateUser(string Nick, string Country)
{
base.Execute("UPDATE accounts SET country=@P0 WHERE name=@P1", Nick, Country);
}
/// <summary>
/// Updates an Account's information by ID
/// </summary>
/// <param name="Id">The Current Account ID</param>
/// <param name="NewPid">New Account ID</param>
/// <param name="NewNick">New Account Name</param>
/// <param name="NewPassword">New Account Password</param>
/// <param name="NewEmail">New Account Email Address</param>
public void UpdateUser(int Id, int NewPid, string NewNick, string NewPassword, string NewEmail)
{
base.Execute("UPDATE accounts SET id=@P0, name=@P1, password=@P2, email=@P3 WHERE id=@P4",
NewPid, NewNick, NewPassword, NewEmail, Id);
}
/// <summary>
/// Deletes a Gamespy Account
/// </summary>
/// <param name="Nick"></param>
/// <returns></returns>
public int DeleteUser(string Nick)
{
return base.Execute("DELETE FROM accounts WHERE name=@P0", Nick);
}
/// <summary>
/// Deletes a Gamespy Account
/// </summary>
/// <param name="Nick"></param>
/// <returns></returns>
public int DeleteUser(int Pid)
{
return base.Execute("DELETE FROM accounts WHERE id=@P0", Pid);
}
/// <summary>
/// Fetches a Gamespy Account id from an account name
/// </summary>
/// <param name="Nick"></param>
/// <returns></returns>
public int GetPID(string Nick)
{
var Rows = base.Query("SELECT id FROM accounts WHERE name=@P0", Nick);
return (Rows.Count == 0) ? 0 : Int32.Parse(Rows[0]["id"].ToString());
}
/// <summary>
/// Sets the Account (Player) Id for an account by Name
/// </summary>
/// <param name="Nick">The account Nick we are setting the new Pid for</param>
/// <param name="Pid">The new Pid</param>
/// <returns></returns>
public int SetPID(string Nick, int Pid)
{
// If no user exists, return code -1
if (!UserExists(Nick))
return -1;
// If the Pid already exists, return -2
if (UserExists(Pid))
return -2;
// If PID is false, the PID is not taken
int Success = base.Execute("UPDATE accounts SET id=@P0 WHERE name=@P1", Pid, Nick);
return (Success > 0) ? 1 : 0;
}
/// <summary>
/// Returns the number of accounts in the database
/// </summary>
/// <returns></returns>
public int GetNumAccounts()
{
var Row = base.Query("SELECT COUNT(id) AS count FROM accounts");
return Int32.Parse(Row[0]["count"].ToString());
}
}
}

BIN
lib/MySql.Data.dll Normal file

Binary file not shown.

BIN
lib/System.Data.SQLite.dll Normal file

Binary file not shown.

5365
lib/System.Data.SQLite.xml Normal file

File diff suppressed because it is too large Load Diff