using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Common; using MySql.Data.MySqlClient; using FLocal.Core; using FLocal.Core.DB; namespace FLocal.MySQLConnector { public class Connection : IDBConnection { private IDBProvider provider; private DbConnection connection; private string connectionString; private HashSet transactions; public Connection(IDBProvider provider, string connectionString) { this.provider = provider; this.connectionString = connectionString; this.connection = this.provider.createConnection(this.connectionString); this.connection.Open(); this.transactions = new HashSet(); } internal DbConnection createConnection() { DbConnection connection = this.provider.createConnection(this.connectionString); connection.Open(); return connection; } public List> LoadByIds(ITableSpec table, List ids) { lock(this) { using(DbCommand command = this.connection.CreateCommand()) { command.CommandType = System.Data.CommandType.Text; ParamsHolder paramsHolder = new ParamsHolder(); List placeholder = new List(); foreach(string id in ids) { placeholder.Add("@" + paramsHolder.Add(id)); } command.CommandText = "SELECT * FROM " + table.compile() + " WHERE " + table.getIdSpec().compile() + " IN (" + string.Join(", ", placeholder.ToArray()) + ")"; command.Prepare(); foreach(KeyValuePair kvp in paramsHolder.data) { command.AddParameter(kvp.Key, kvp.Value); } Dictionary> rawResult = new Dictionary>(); using(DbDataReader reader = command.ExecuteReader()) { while(reader.Read()) { Dictionary row = new Dictionary(); for(int i=0; i> result = new List>(); foreach(string id in ids) { if(rawResult.ContainsKey(id)) { result.Add(rawResult[id]); } } return result; } } } public List LoadIdsByConditions(ITableSpec table, FLocal.Core.DB.conditions.AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts) { lock(this) { using(DbCommand command = this.connection.CreateCommand()) { command.CommandType = System.Data.CommandType.Text; var conditionsCompiled = ConditionCompiler.Compile(conditions); string queryConditions = conditionsCompiled.Key; ParamsHolder paramsHolder = conditionsCompiled.Value; string queryJoins = ""; string querySorts = ""; { } string queryMain = "FROM " + table.compile() + " " + queryJoins + " WHERE " + queryConditions; foreach(KeyValuePair kvp in paramsHolder.data) { command.AddParameter(kvp.Key, kvp.Value); } command.CommandText = "SELECT COUNT(*) " + queryMain; object rawCount = command.ExecuteScalar(); int count = (int)rawCount; if(count < 1) { diapasone.total = 0; return new List(); } else { diapasone.total = count; string queryLimits = ""; if(diapasone.count >= 0) { queryLimits = "LIMIT " + diapasone.count + " OFFSET " + diapasone.start; } command.CommandText = "SELECT " + table.compile() + ".* " + queryMain + " " + querySorts + " " + queryLimits; List result = new List(); using(DbDataReader reader = command.ExecuteReader()) { while(reader.Read()) { result.Add(reader.GetString(0)); } } return result; } } } } public FLocal.Core.DB.Transaction beginTransaction(System.Data.IsolationLevel iso) { lock(this) { Transaction transaction = new Transaction(this, iso); try { this.transactions.Add(transaction); } catch(Exception e) { transaction.Dispose(); throw e; } return transaction; } } public void lockTable(FLocal.Core.DB.Transaction _transaction, ITableSpec table) { Transaction transaction = (Transaction)_transaction; lock(transaction) { using(DbCommand command = transaction.sqlconnection.CreateCommand()) { command.Transaction = transaction.sqltransaction; command.CommandType = System.Data.CommandType.Text; command.CommandText = "LOCK TABLES `" + MySqlHelper.EscapeString(table.name) + "`"; command.ExecuteNonQuery(); } } } public void lockRow(FLocal.Core.DB.Transaction _transaction, ITableSpec table, string id) { Transaction transaction = (Transaction)_transaction; lock(transaction) { using(DbCommand command = transaction.sqlconnection.CreateCommand()) { command.Transaction = transaction.sqltransaction; command.CommandType = System.Data.CommandType.Text; command.CommandText = "SELECT * FROM `" + MySqlHelper.EscapeString(table.name) + "` where `" + MySqlHelper.EscapeString(table.idName) + "` = @id FOR UPDATE"; command.AddParameter("id", id); command.ExecuteNonQuery(); } } } public void update(FLocal.Core.DB.Transaction _transaction, ITableSpec table, string id, Dictionary data) { Transaction transaction = (Transaction)_transaction; lock(transaction) { using(DbCommand command = transaction.sqlconnection.CreateCommand()) { List updates = new List(); ParamsHolder paramsholder = new ParamsHolder(); foreach(KeyValuePair kvp in data) { string paramname = paramsholder.Add(kvp.Value); updates.Add("`" + MySqlHelper.EscapeString(kvp.Key) + "` = @" + paramname); } command.Transaction = transaction.sqltransaction; command.CommandType = System.Data.CommandType.Text; command.CommandText = "UPDATE `" + MySqlHelper.EscapeString(table.name) + "` set " + String.Join(", ", updates.ToArray()) + " where `" + MySqlHelper.EscapeString(table.idName) + "` = @id"; command.AddParameter("id", id); foreach(KeyValuePair kvp in paramsholder.data) { command.AddParameter(kvp.Key, kvp.Value); } command.ExecuteNonQuery(); } } } public string insert(FLocal.Core.DB.Transaction _transaction, ITableSpec table, Dictionary data) { Transaction transaction = (Transaction)_transaction; lock(transaction) { using(DbCommand command = transaction.sqlconnection.CreateCommand()) { List updates = new List(); ParamsHolder paramsholder = new ParamsHolder(); foreach(KeyValuePair kvp in data) { string paramname = paramsholder.Add(kvp.Value); updates.Add("`" + MySqlHelper.EscapeString(kvp.Key) + "` = @" + paramname); } command.Transaction = transaction.sqltransaction; command.CommandType = System.Data.CommandType.Text; command.CommandText = "INSERT INTO `" + MySqlHelper.EscapeString(table.name) + "` SET " + String.Join(", ", updates.ToArray()); foreach(KeyValuePair kvp in paramsholder.data) { command.AddParameter(kvp.Key, kvp.Value); } command.ExecuteNonQuery(); return this.provider.LastInsertId(command).ToString(); } } } public void delete(FLocal.Core.DB.Transaction transaction, ITableSpec table, string id) { throw new NotImplementedException(); } public void Dispose() { lock(this) { foreach(Transaction transaction in this.transactions) { if(!transaction.finalizedImpl) { throw new CriticalException("Trying to close db connection while there are open transactions"); } } this.transactions.Clear(); this.transactions = null; this.connection.Close(); this.connection.Dispose(); this.connection = null; } } } }